Home | History | Annotate | Download | only in glshared
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL (ES) 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 Draw tests
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "glsDrawTest.hpp"
     25 
     26 #include "deRandom.h"
     27 #include "deRandom.hpp"
     28 #include "deMath.h"
     29 #include "deStringUtil.hpp"
     30 #include "deFloat16.h"
     31 #include "deUniquePtr.hpp"
     32 
     33 #include "tcuTestLog.hpp"
     34 #include "tcuPixelFormat.hpp"
     35 #include "tcuRGBA.hpp"
     36 #include "tcuSurface.hpp"
     37 #include "tcuVector.hpp"
     38 #include "tcuTestLog.hpp"
     39 #include "tcuRenderTarget.hpp"
     40 #include "tcuStringTemplate.hpp"
     41 #include "tcuImageCompare.hpp"
     42 #include "tcuFloat.hpp"
     43 #include "tcuTextureUtil.hpp"
     44 
     45 #include "gluPixelTransfer.hpp"
     46 #include "gluCallLogWrapper.hpp"
     47 
     48 #include "sglrContext.hpp"
     49 #include "sglrReferenceContext.hpp"
     50 #include "sglrGLContext.hpp"
     51 
     52 #include "rrGenericVector.hpp"
     53 
     54 #include <cstring>
     55 #include <cmath>
     56 #include <vector>
     57 #include <sstream>
     58 #include <limits>
     59 
     60 #include "glwDefs.hpp"
     61 #include "glwEnums.hpp"
     62 
     63 
     64 namespace deqp
     65 {
     66 namespace gls
     67 {
     68 namespace
     69 {
     70 
     71 using tcu::TestLog;
     72 using namespace glw; // GL types
     73 
     74 const int MAX_RENDER_TARGET_SIZE = 512;
     75 
     76 // Utils
     77 
     78 static GLenum targetToGL (DrawTestSpec::Target target)
     79 {
     80 	DE_ASSERT(target < DrawTestSpec::TARGET_LAST);
     81 
     82 	static const GLenum targets[] =
     83 	{
     84 		GL_ELEMENT_ARRAY_BUFFER,	// TARGET_ELEMENT_ARRAY = 0,
     85 		GL_ARRAY_BUFFER				// TARGET_ARRAY,
     86 	};
     87 
     88 	return targets[(int)target];
     89 }
     90 
     91 static GLenum usageToGL (DrawTestSpec::Usage usage)
     92 {
     93 	DE_ASSERT(usage < DrawTestSpec::USAGE_LAST);
     94 
     95 	static const GLenum usages[] =
     96 	{
     97 		GL_DYNAMIC_DRAW,	// USAGE_DYNAMIC_DRAW = 0,
     98 		GL_STATIC_DRAW,		// USAGE_STATIC_DRAW,
     99 		GL_STREAM_DRAW,		// USAGE_STREAM_DRAW,
    100 
    101 		GL_STREAM_READ,		// USAGE_STREAM_READ,
    102 		GL_STREAM_COPY,		// USAGE_STREAM_COPY,
    103 
    104 		GL_STATIC_READ,		// USAGE_STATIC_READ,
    105 		GL_STATIC_COPY,		// USAGE_STATIC_COPY,
    106 
    107 		GL_DYNAMIC_READ,	// USAGE_DYNAMIC_READ,
    108 		GL_DYNAMIC_COPY		// USAGE_DYNAMIC_COPY,
    109 	};
    110 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(usages) == DrawTestSpec::USAGE_LAST);
    111 
    112 	return usages[(int)usage];
    113 }
    114 
    115 static GLenum inputTypeToGL (DrawTestSpec::InputType type)
    116 {
    117 	DE_ASSERT(type < DrawTestSpec::INPUTTYPE_LAST);
    118 
    119 	static const GLenum types[] =
    120 	{
    121 		GL_FLOAT,				// INPUTTYPE_FLOAT = 0,
    122 		GL_FIXED,				// INPUTTYPE_FIXED,
    123 		GL_DOUBLE,				// INPUTTYPE_DOUBLE
    124 		GL_BYTE,				// INPUTTYPE_BYTE,
    125 		GL_SHORT,				// INPUTTYPE_SHORT,
    126 		GL_UNSIGNED_BYTE,		// INPUTTYPE_UNSIGNED_BYTE,
    127 		GL_UNSIGNED_SHORT,		// INPUTTYPE_UNSIGNED_SHORT,
    128 
    129 		GL_INT,					// INPUTTYPE_INT,
    130 		GL_UNSIGNED_INT,		// INPUTTYPE_UNSIGNED_INT,
    131 		GL_HALF_FLOAT,			// INPUTTYPE_HALF,
    132 		GL_UNSIGNED_INT_2_10_10_10_REV, // INPUTTYPE_UNSIGNED_INT_2_10_10_10,
    133 		GL_INT_2_10_10_10_REV			// INPUTTYPE_INT_2_10_10_10,
    134 	};
    135 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(types) == DrawTestSpec::INPUTTYPE_LAST);
    136 
    137 	return types[(int)type];
    138 }
    139 
    140 static std::string outputTypeToGLType (DrawTestSpec::OutputType type)
    141 {
    142 	DE_ASSERT(type < DrawTestSpec::OUTPUTTYPE_LAST);
    143 
    144 	static const char* types[] =
    145 	{
    146 		"float",		// OUTPUTTYPE_FLOAT = 0,
    147 		"vec2",			// OUTPUTTYPE_VEC2,
    148 		"vec3",			// OUTPUTTYPE_VEC3,
    149 		"vec4",			// OUTPUTTYPE_VEC4,
    150 
    151 		"int",			// OUTPUTTYPE_INT,
    152 		"uint",			// OUTPUTTYPE_UINT,
    153 
    154 		"ivec2",		// OUTPUTTYPE_IVEC2,
    155 		"ivec3",		// OUTPUTTYPE_IVEC3,
    156 		"ivec4",		// OUTPUTTYPE_IVEC4,
    157 
    158 		"uvec2",		// OUTPUTTYPE_UVEC2,
    159 		"uvec3",		// OUTPUTTYPE_UVEC3,
    160 		"uvec4",		// OUTPUTTYPE_UVEC4,
    161 	};
    162 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(types) == DrawTestSpec::OUTPUTTYPE_LAST);
    163 
    164 	return types[type];
    165 }
    166 
    167 static GLenum primitiveToGL (DrawTestSpec::Primitive primitive)
    168 {
    169 	GLenum primitives[] =
    170 	{
    171 		GL_POINTS,						// PRIMITIVE_POINTS = 0,
    172 		GL_TRIANGLES,					// PRIMITIVE_TRIANGLES,
    173 		GL_TRIANGLE_FAN,				// PRIMITIVE_TRIANGLE_FAN,
    174 		GL_TRIANGLE_STRIP,				// PRIMITIVE_TRIANGLE_STRIP,
    175 		GL_LINES,						// PRIMITIVE_LINES
    176 		GL_LINE_STRIP,					// PRIMITIVE_LINE_STRIP
    177 		GL_LINE_LOOP,					// PRIMITIVE_LINE_LOOP
    178 		GL_LINES_ADJACENCY,				// PRIMITIVE_LINES_ADJACENCY
    179 		GL_LINE_STRIP_ADJACENCY,		// PRIMITIVE_LINE_STRIP_ADJACENCY
    180 		GL_TRIANGLES_ADJACENCY,			// PRIMITIVE_TRIANGLES_ADJACENCY
    181 		GL_TRIANGLE_STRIP_ADJACENCY,	// PRIMITIVE_TRIANGLE_STRIP_ADJACENCY
    182 	};
    183 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(primitives) == DrawTestSpec::PRIMITIVE_LAST);
    184 
    185 	return primitives[(int)primitive];
    186 }
    187 
    188 static deUint32 indexTypeToGL (DrawTestSpec::IndexType indexType)
    189 {
    190 	GLenum indexTypes[] =
    191 	{
    192 		GL_UNSIGNED_BYTE,	// INDEXTYPE_BYTE = 0,
    193 		GL_UNSIGNED_SHORT,	// INDEXTYPE_SHORT,
    194 		GL_UNSIGNED_INT,	// INDEXTYPE_INT,
    195 	};
    196 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(indexTypes) == DrawTestSpec::INDEXTYPE_LAST);
    197 
    198 	return indexTypes[(int)indexType];
    199 }
    200 
    201 static bool inputTypeIsFloatType (DrawTestSpec::InputType type)
    202 {
    203 	if (type == DrawTestSpec::INPUTTYPE_FLOAT)
    204 		return true;
    205 	if (type == DrawTestSpec::INPUTTYPE_FIXED)
    206 		return true;
    207 	if (type == DrawTestSpec::INPUTTYPE_HALF)
    208 		return true;
    209 	if (type == DrawTestSpec::INPUTTYPE_DOUBLE)
    210 		return true;
    211 	return false;
    212 }
    213 
    214 static bool outputTypeIsFloatType (DrawTestSpec::OutputType type)
    215 {
    216 	if (type == DrawTestSpec::OUTPUTTYPE_FLOAT
    217 		|| type == DrawTestSpec::OUTPUTTYPE_VEC2
    218 		|| type == DrawTestSpec::OUTPUTTYPE_VEC3
    219 		|| type == DrawTestSpec::OUTPUTTYPE_VEC4)
    220 		return true;
    221 
    222 	return false;
    223 }
    224 
    225 static bool outputTypeIsIntType (DrawTestSpec::OutputType type)
    226 {
    227 	if (type == DrawTestSpec::OUTPUTTYPE_INT
    228 		|| type == DrawTestSpec::OUTPUTTYPE_IVEC2
    229 		|| type == DrawTestSpec::OUTPUTTYPE_IVEC3
    230 		|| type == DrawTestSpec::OUTPUTTYPE_IVEC4)
    231 		return true;
    232 
    233 	return false;
    234 }
    235 
    236 static bool outputTypeIsUintType (DrawTestSpec::OutputType type)
    237 {
    238 	if (type == DrawTestSpec::OUTPUTTYPE_UINT
    239 		|| type == DrawTestSpec::OUTPUTTYPE_UVEC2
    240 		|| type == DrawTestSpec::OUTPUTTYPE_UVEC3
    241 		|| type == DrawTestSpec::OUTPUTTYPE_UVEC4)
    242 		return true;
    243 
    244 	return false;
    245 }
    246 
    247 static size_t getElementCount (DrawTestSpec::Primitive primitive, size_t primitiveCount)
    248 {
    249 	switch (primitive)
    250 	{
    251 		case DrawTestSpec::PRIMITIVE_POINTS:						return primitiveCount;
    252 		case DrawTestSpec::PRIMITIVE_TRIANGLES:						return primitiveCount * 3;
    253 		case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:					return primitiveCount + 2;
    254 		case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:				return primitiveCount + 2;
    255 		case DrawTestSpec::PRIMITIVE_LINES:							return primitiveCount * 2;
    256 		case DrawTestSpec::PRIMITIVE_LINE_STRIP:					return primitiveCount + 1;
    257 		case DrawTestSpec::PRIMITIVE_LINE_LOOP:						return (primitiveCount==1) ? (2) : (primitiveCount);
    258 		case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:				return primitiveCount * 4;
    259 		case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:			return primitiveCount + 3;
    260 		case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:			return primitiveCount * 6;
    261 		case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:		return primitiveCount * 2 + 4;
    262 		default:
    263 			DE_ASSERT(false);
    264 			return 0;
    265 	}
    266 }
    267 
    268 struct MethodInfo
    269 {
    270 	bool indexed;
    271 	bool instanced;
    272 	bool ranged;
    273 	bool first;
    274 	bool baseVertex;
    275 	bool indirect;
    276 };
    277 
    278 static MethodInfo getMethodInfo (gls::DrawTestSpec::DrawMethod method)
    279 {
    280 	static const MethodInfo infos[] =
    281 	{
    282 		//	indexed		instanced	ranged		first		baseVertex	indirect
    283 		{	false,		false,		false,		true,		false,		false	}, //!< DRAWMETHOD_DRAWARRAYS,
    284 		{	false,		true,		false,		true,		false,		false	}, //!< DRAWMETHOD_DRAWARRAYS_INSTANCED,
    285 		{	false,		true,		false,		true,		false,		true	}, //!< DRAWMETHOD_DRAWARRAYS_INDIRECT,
    286 		{	true,		false,		false,		false,		false,		false	}, //!< DRAWMETHOD_DRAWELEMENTS,
    287 		{	true,		false,		true,		false,		false,		false	}, //!< DRAWMETHOD_DRAWELEMENTS_RANGED,
    288 		{	true,		true,		false,		false,		false,		false	}, //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED,
    289 		{	true,		true,		false,		false,		true,		true	}, //!< DRAWMETHOD_DRAWELEMENTS_INDIRECT,
    290 		{	true,		false,		false,		false,		true,		false	}, //!< DRAWMETHOD_DRAWELEMENTS_BASEVERTEX,
    291 		{	true,		true,		false,		false,		true,		false	}, //!< DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX,
    292 		{	true,		false,		true,		false,		true,		false	}, //!< DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX,
    293 	};
    294 
    295 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(infos) == DrawTestSpec::DRAWMETHOD_LAST);
    296 	DE_ASSERT((int)method < DE_LENGTH_OF_ARRAY(infos));
    297 	return infos[(int)method];
    298 }
    299 
    300 template<class T>
    301 inline static void alignmentSafeAssignment (char* dst, T val)
    302 {
    303 	std::memcpy(dst, &val, sizeof(T));
    304 }
    305 
    306 static bool checkSpecsShaderCompatible (const DrawTestSpec& a, const DrawTestSpec& b)
    307 {
    308 	// Only the attributes matter
    309 	if (a.attribs.size() != b.attribs.size())
    310 		return false;
    311 
    312 	for (size_t ndx = 0; ndx < a.attribs.size(); ++ndx)
    313 	{
    314 		// Only the output type (== shader input type) matters and the usage in the shader.
    315 
    316 		if (a.attribs[ndx].additionalPositionAttribute != b.attribs[ndx].additionalPositionAttribute)
    317 			return false;
    318 
    319 		// component counts need not to match
    320 		if (outputTypeIsFloatType(a.attribs[ndx].outputType) && outputTypeIsFloatType(b.attribs[ndx].outputType))
    321 			continue;
    322 		if (outputTypeIsIntType(a.attribs[ndx].outputType) && outputTypeIsIntType(b.attribs[ndx].outputType))
    323 			continue;
    324 		if (outputTypeIsUintType(a.attribs[ndx].outputType) && outputTypeIsUintType(b.attribs[ndx].outputType))
    325 			continue;
    326 
    327 		return false;
    328 	}
    329 
    330 	return true;
    331 }
    332 
    333 // generate random vectors in a way that does not depend on argument evaluation order
    334 
    335 tcu::Vec4 generateRandomVec4 (de::Random& random)
    336 {
    337 	tcu::Vec4 retVal;
    338 
    339 	for (int i = 0; i < 4; ++i)
    340 		retVal[i] = random.getFloat();
    341 
    342 	return retVal;
    343 }
    344 
    345 tcu::IVec4 generateRandomIVec4 (de::Random& random)
    346 {
    347 	tcu::IVec4 retVal;
    348 
    349 	for (int i = 0; i < 4; ++i)
    350 		retVal[i] = random.getUint32();
    351 
    352 	return retVal;
    353 }
    354 
    355 tcu::UVec4 generateRandomUVec4 (de::Random& random)
    356 {
    357 	tcu::UVec4 retVal;
    358 
    359 	for (int i = 0; i < 4; ++i)
    360 		retVal[i] = random.getUint32();
    361 
    362 	return retVal;
    363 }
    364 
    365 // IterationLogSectionEmitter
    366 
    367 class IterationLogSectionEmitter
    368 {
    369 public:
    370 								IterationLogSectionEmitter		(tcu::TestLog& log, size_t testIteration, size_t testIterations, const std::string& description, bool enabled);
    371 								~IterationLogSectionEmitter		(void);
    372 private:
    373 								IterationLogSectionEmitter		(const IterationLogSectionEmitter&); // delete
    374 	IterationLogSectionEmitter&	operator=						(const IterationLogSectionEmitter&); // delete
    375 
    376 	tcu::TestLog&				m_log;
    377 	bool						m_enabled;
    378 };
    379 
    380 IterationLogSectionEmitter::IterationLogSectionEmitter (tcu::TestLog& log, size_t testIteration, size_t testIterations, const std::string& description, bool enabled)
    381 	: m_log		(log)
    382 	, m_enabled	(enabled)
    383 {
    384 	if (m_enabled)
    385 	{
    386 		std::ostringstream buf;
    387 		buf << "Iteration " << (testIteration+1) << "/" << testIterations;
    388 
    389 		if (!description.empty())
    390 			buf << " - " << description;
    391 
    392 		m_log << tcu::TestLog::Section(buf.str(), buf.str());
    393 	}
    394 }
    395 
    396 IterationLogSectionEmitter::~IterationLogSectionEmitter (void)
    397 {
    398 	if (m_enabled)
    399 		m_log << tcu::TestLog::EndSection;
    400 }
    401 
    402 // GLValue
    403 
    404 class GLValue
    405 {
    406 public:
    407 
    408 	template<class Type>
    409 	class WrappedType
    410 	{
    411 	public:
    412 		static WrappedType<Type>	create			(Type value)							{ WrappedType<Type> v; v.m_value = value; return v; }
    413 		inline Type					getValue		(void) const							{ return m_value; }
    414 
    415 		inline WrappedType<Type>	operator+		(const WrappedType<Type>& other) const	{ return WrappedType<Type>::create(m_value + other.getValue()); }
    416 		inline WrappedType<Type>	operator*		(const WrappedType<Type>& other) const	{ return WrappedType<Type>::create(m_value * other.getValue()); }
    417 		inline WrappedType<Type>	operator/		(const WrappedType<Type>& other) const	{ return WrappedType<Type>::create(m_value / other.getValue()); }
    418 		inline WrappedType<Type>	operator-		(const WrappedType<Type>& other) const	{ return WrappedType<Type>::create(m_value - other.getValue()); }
    419 
    420 		inline WrappedType<Type>&	operator+=		(const WrappedType<Type>& other)		{ m_value += other.getValue(); return *this; }
    421 		inline WrappedType<Type>&	operator*=		(const WrappedType<Type>& other)		{ m_value *= other.getValue(); return *this; }
    422 		inline WrappedType<Type>&	operator/=		(const WrappedType<Type>& other)		{ m_value /= other.getValue(); return *this; }
    423 		inline WrappedType<Type>&	operator-=		(const WrappedType<Type>& other)		{ m_value -= other.getValue(); return *this; }
    424 
    425 		inline bool					operator==		(const WrappedType<Type>& other) const	{ return m_value == other.m_value; }
    426 		inline bool					operator!=		(const WrappedType<Type>& other) const	{ return m_value != other.m_value; }
    427 		inline bool					operator<		(const WrappedType<Type>& other) const	{ return m_value < other.m_value; }
    428 		inline bool					operator>		(const WrappedType<Type>& other) const	{ return m_value > other.m_value; }
    429 		inline bool					operator<=		(const WrappedType<Type>& other) const	{ return m_value <= other.m_value; }
    430 		inline bool					operator>=		(const WrappedType<Type>& other) const	{ return m_value >= other.m_value; }
    431 
    432 		inline 						operator Type	(void) const							{ return m_value; }
    433 		template<class T>
    434 		inline T					to				(void) const							{ return (T)m_value; }
    435 	private:
    436 		Type	m_value;
    437 	};
    438 
    439 	typedef WrappedType<deInt16>	Short;
    440 	typedef WrappedType<deUint16>	Ushort;
    441 
    442 	typedef WrappedType<deInt8>		Byte;
    443 	typedef WrappedType<deUint8>	Ubyte;
    444 
    445 	typedef WrappedType<float>		Float;
    446 	typedef WrappedType<double>		Double;
    447 
    448 	typedef WrappedType<deInt32>	Int;
    449 	typedef WrappedType<deUint32>	Uint;
    450 
    451 	class Half
    452 	{
    453 	public:
    454 		static Half			create			(float value)				{ Half h; h.m_value = floatToHalf(value); return h; }
    455 		inline deFloat16	getValue		(void) const				{ return m_value; }
    456 
    457 		inline Half			operator+		(const Half& other) const	{ return create(halfToFloat(m_value) + halfToFloat(other.getValue())); }
    458 		inline Half			operator*		(const Half& other) const	{ return create(halfToFloat(m_value) * halfToFloat(other.getValue())); }
    459 		inline Half			operator/		(const Half& other) const	{ return create(halfToFloat(m_value) / halfToFloat(other.getValue())); }
    460 		inline Half			operator-		(const Half& other) const	{ return create(halfToFloat(m_value) - halfToFloat(other.getValue())); }
    461 
    462 		inline Half&		operator+=		(const Half& other)			{ m_value = floatToHalf(halfToFloat(other.getValue()) + halfToFloat(m_value)); return *this; }
    463 		inline Half&		operator*=		(const Half& other)			{ m_value = floatToHalf(halfToFloat(other.getValue()) * halfToFloat(m_value)); return *this; }
    464 		inline Half&		operator/=		(const Half& other)			{ m_value = floatToHalf(halfToFloat(other.getValue()) / halfToFloat(m_value)); return *this; }
    465 		inline Half&		operator-=		(const Half& other)			{ m_value = floatToHalf(halfToFloat(other.getValue()) - halfToFloat(m_value)); return *this; }
    466 
    467 		inline bool			operator==		(const Half& other) const	{ return m_value == other.m_value; }
    468 		inline bool			operator!=		(const Half& other) const	{ return m_value != other.m_value; }
    469 		inline bool			operator<		(const Half& other) const	{ return halfToFloat(m_value) < halfToFloat(other.m_value); }
    470 		inline bool			operator>		(const Half& other) const	{ return halfToFloat(m_value) > halfToFloat(other.m_value); }
    471 		inline bool			operator<=		(const Half& other) const	{ return halfToFloat(m_value) <= halfToFloat(other.m_value); }
    472 		inline bool			operator>=		(const Half& other) const	{ return halfToFloat(m_value) >= halfToFloat(other.m_value); }
    473 
    474 		template<class T>
    475 		inline T			to				(void) const				{ return (T)halfToFloat(m_value); }
    476 
    477 		inline static deFloat16	floatToHalf		(float f);
    478 		inline static float		halfToFloat		(deFloat16 h);
    479 	private:
    480 		deFloat16 m_value;
    481 	};
    482 
    483 	class Fixed
    484 	{
    485 	public:
    486 		static Fixed		create			(deInt32 value)				{ Fixed v; v.m_value = value; return v; }
    487 		inline deInt32		getValue		(void) const				{ return m_value; }
    488 
    489 		inline Fixed		operator+		(const Fixed& other) const	{ return create(m_value + other.getValue()); }
    490 		inline Fixed		operator*		(const Fixed& other) const	{ return create(m_value * other.getValue()); }
    491 		inline Fixed		operator/		(const Fixed& other) const	{ return create(m_value / other.getValue()); }
    492 		inline Fixed		operator-		(const Fixed& other) const	{ return create(m_value - other.getValue()); }
    493 
    494 		inline Fixed&		operator+=		(const Fixed& other)		{ m_value += other.getValue(); return *this; }
    495 		inline Fixed&		operator*=		(const Fixed& other)		{ m_value *= other.getValue(); return *this; }
    496 		inline Fixed&		operator/=		(const Fixed& other)		{ m_value /= other.getValue(); return *this; }
    497 		inline Fixed&		operator-=		(const Fixed& other)		{ m_value -= other.getValue(); return *this; }
    498 
    499 		inline bool			operator==		(const Fixed& other) const	{ return m_value == other.m_value; }
    500 		inline bool			operator!=		(const Fixed& other) const	{ return m_value != other.m_value; }
    501 		inline bool			operator<		(const Fixed& other) const	{ return m_value < other.m_value; }
    502 		inline bool			operator>		(const Fixed& other) const	{ return m_value > other.m_value; }
    503 		inline bool			operator<=		(const Fixed& other) const	{ return m_value <= other.m_value; }
    504 		inline bool			operator>=		(const Fixed& other) const	{ return m_value >= other.m_value; }
    505 
    506 		inline 				operator deInt32 (void) const				{ return m_value; }
    507 		template<class T>
    508 		inline T			to				(void) const				{ return (T)m_value; }
    509 	private:
    510 		deInt32				m_value;
    511 	};
    512 
    513 	// \todo [mika] This is pretty messy
    514 						GLValue			(void)			: type(DrawTestSpec::INPUTTYPE_LAST) {}
    515 	explicit			GLValue			(Float value)	: type(DrawTestSpec::INPUTTYPE_FLOAT),				fl(value)	{}
    516 	explicit			GLValue			(Fixed value)	: type(DrawTestSpec::INPUTTYPE_FIXED),				fi(value)	{}
    517 	explicit			GLValue			(Byte value)	: type(DrawTestSpec::INPUTTYPE_BYTE),				b(value)	{}
    518 	explicit			GLValue			(Ubyte value)	: type(DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE),		ub(value)	{}
    519 	explicit			GLValue			(Short value)	: type(DrawTestSpec::INPUTTYPE_SHORT),				s(value)	{}
    520 	explicit			GLValue			(Ushort value)	: type(DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT),		us(value)	{}
    521 	explicit			GLValue			(Int value)		: type(DrawTestSpec::INPUTTYPE_INT),				i(value)	{}
    522 	explicit			GLValue			(Uint value)	: type(DrawTestSpec::INPUTTYPE_UNSIGNED_INT),		ui(value)	{}
    523 	explicit			GLValue			(Half value)	: type(DrawTestSpec::INPUTTYPE_HALF),				h(value)	{}
    524 	explicit			GLValue			(Double value)	: type(DrawTestSpec::INPUTTYPE_DOUBLE),				d(value)	{}
    525 
    526 	float				toFloat			(void) const;
    527 
    528 	static GLValue		getMaxValue		(DrawTestSpec::InputType type);
    529 	static GLValue		getMinValue		(DrawTestSpec::InputType type);
    530 
    531 	DrawTestSpec::InputType	type;
    532 
    533 	union
    534 	{
    535 		Float		fl;
    536 		Fixed		fi;
    537 		Double		d;
    538 		Byte		b;
    539 		Ubyte		ub;
    540 		Short		s;
    541 		Ushort		us;
    542 		Int			i;
    543 		Uint		ui;
    544 		Half		h;
    545 	};
    546 };
    547 
    548 inline deFloat16 GLValue::Half::floatToHalf (float f)
    549 {
    550 	// No denorm support.
    551 	tcu::Float<deUint16, 5, 10, 15, tcu::FLOAT_HAS_SIGN> v(f);
    552 	DE_ASSERT(!v.isNaN() && !v.isInf());
    553 	return v.bits();
    554 }
    555 
    556 inline float GLValue::Half::halfToFloat (deFloat16 h)
    557 {
    558 	return tcu::Float16((deUint16)h).asFloat();
    559 }
    560 
    561 float GLValue::toFloat (void) const
    562 {
    563 	switch (type)
    564 	{
    565 		case DrawTestSpec::INPUTTYPE_FLOAT:
    566 			return fl.getValue();
    567 			break;
    568 
    569 		case DrawTestSpec::INPUTTYPE_BYTE:
    570 			return b.getValue();
    571 			break;
    572 
    573 		case DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE:
    574 			return ub.getValue();
    575 			break;
    576 
    577 		case DrawTestSpec::INPUTTYPE_SHORT:
    578 			return s.getValue();
    579 			break;
    580 
    581 		case DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT:
    582 			return us.getValue();
    583 			break;
    584 
    585 		case DrawTestSpec::INPUTTYPE_FIXED:
    586 		{
    587 			int maxValue = 65536;
    588 			return (float)(double(2 * fi.getValue() + 1) / (maxValue - 1));
    589 
    590 			break;
    591 		}
    592 
    593 		case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:
    594 			return (float)ui.getValue();
    595 			break;
    596 
    597 		case DrawTestSpec::INPUTTYPE_INT:
    598 			return (float)i.getValue();
    599 			break;
    600 
    601 		case DrawTestSpec::INPUTTYPE_HALF:
    602 			return h.to<float>();
    603 			break;
    604 
    605 		case DrawTestSpec::INPUTTYPE_DOUBLE:
    606 			return d.to<float>();
    607 			break;
    608 
    609 		default:
    610 			DE_ASSERT(false);
    611 			return 0.0f;
    612 			break;
    613 	};
    614 }
    615 
    616 GLValue GLValue::getMaxValue (DrawTestSpec::InputType type)
    617 {
    618 	GLValue rangesHi[(int)DrawTestSpec::INPUTTYPE_LAST];
    619 
    620 	rangesHi[(int)DrawTestSpec::INPUTTYPE_FLOAT]			= GLValue(Float::create(127.0f));
    621 	rangesHi[(int)DrawTestSpec::INPUTTYPE_DOUBLE]			= GLValue(Double::create(127.0f));
    622 	rangesHi[(int)DrawTestSpec::INPUTTYPE_BYTE]				= GLValue(Byte::create(127));
    623 	rangesHi[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE]	= GLValue(Ubyte::create(255));
    624 	rangesHi[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT]	= GLValue(Ushort::create(65530));
    625 	rangesHi[(int)DrawTestSpec::INPUTTYPE_SHORT]			= GLValue(Short::create(32760));
    626 	rangesHi[(int)DrawTestSpec::INPUTTYPE_FIXED]			= GLValue(Fixed::create(32760));
    627 	rangesHi[(int)DrawTestSpec::INPUTTYPE_INT]				= GLValue(Int::create(2147483647));
    628 	rangesHi[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_INT]		= GLValue(Uint::create(4294967295u));
    629 	rangesHi[(int)DrawTestSpec::INPUTTYPE_HALF]				= GLValue(Half::create(256.0f));
    630 
    631 	return rangesHi[(int)type];
    632 }
    633 
    634 GLValue GLValue::getMinValue (DrawTestSpec::InputType type)
    635 {
    636 	GLValue rangesLo[(int)DrawTestSpec::INPUTTYPE_LAST];
    637 
    638 	rangesLo[(int)DrawTestSpec::INPUTTYPE_FLOAT]			= GLValue(Float::create(-127.0f));
    639 	rangesLo[(int)DrawTestSpec::INPUTTYPE_DOUBLE]			= GLValue(Double::create(-127.0f));
    640 	rangesLo[(int)DrawTestSpec::INPUTTYPE_BYTE]				= GLValue(Byte::create(-127));
    641 	rangesLo[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE]	= GLValue(Ubyte::create(0));
    642 	rangesLo[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT]	= GLValue(Ushort::create(0));
    643 	rangesLo[(int)DrawTestSpec::INPUTTYPE_SHORT]			= GLValue(Short::create(-32760));
    644 	rangesLo[(int)DrawTestSpec::INPUTTYPE_FIXED]			= GLValue(Fixed::create(-32760));
    645 	rangesLo[(int)DrawTestSpec::INPUTTYPE_INT]				= GLValue(Int::create(-2147483647));
    646 	rangesLo[(int)DrawTestSpec::INPUTTYPE_UNSIGNED_INT]		= GLValue(Uint::create(0));
    647 	rangesLo[(int)DrawTestSpec::INPUTTYPE_HALF]				= GLValue(Half::create(-256.0f));
    648 
    649 	return rangesLo[(int)type];
    650 }
    651 
    652 template<typename T>
    653 struct GLValueTypeTraits;
    654 
    655 template<> struct GLValueTypeTraits<GLValue::Float>	 { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_FLOAT;			};
    656 template<> struct GLValueTypeTraits<GLValue::Double> { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_DOUBLE;			};
    657 template<> struct GLValueTypeTraits<GLValue::Byte>	 { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_BYTE;			};
    658 template<> struct GLValueTypeTraits<GLValue::Ubyte>	 { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE;	};
    659 template<> struct GLValueTypeTraits<GLValue::Ushort> { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT;	};
    660 template<> struct GLValueTypeTraits<GLValue::Short>	 { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_SHORT;			};
    661 template<> struct GLValueTypeTraits<GLValue::Fixed>	 { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_FIXED;			};
    662 template<> struct GLValueTypeTraits<GLValue::Int>	 { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_INT;			};
    663 template<> struct GLValueTypeTraits<GLValue::Uint>	 { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_UNSIGNED_INT;	};
    664 template<> struct GLValueTypeTraits<GLValue::Half>	 { static const DrawTestSpec::InputType Type = DrawTestSpec::INPUTTYPE_HALF;			};
    665 
    666 template<typename T>
    667 inline T extractGLValue (const GLValue& v);
    668 
    669 template<> GLValue::Float	inline extractGLValue<GLValue::Float>		(const GLValue& v) { return v.fl; };
    670 template<> GLValue::Double	inline extractGLValue<GLValue::Double>		(const GLValue& v) { return v.d; };
    671 template<> GLValue::Byte	inline extractGLValue<GLValue::Byte>		(const GLValue& v) { return v.b; };
    672 template<> GLValue::Ubyte	inline extractGLValue<GLValue::Ubyte>		(const GLValue& v) { return v.ub; };
    673 template<> GLValue::Ushort	inline extractGLValue<GLValue::Ushort>		(const GLValue& v) { return v.us; };
    674 template<> GLValue::Short	inline extractGLValue<GLValue::Short>		(const GLValue& v) { return v.s; };
    675 template<> GLValue::Fixed	inline extractGLValue<GLValue::Fixed>		(const GLValue& v) { return v.fi; };
    676 template<> GLValue::Int		inline extractGLValue<GLValue::Int>			(const GLValue& v) { return v.i; };
    677 template<> GLValue::Uint	inline extractGLValue<GLValue::Uint>		(const GLValue& v) { return v.ui; };
    678 template<> GLValue::Half	inline extractGLValue<GLValue::Half>		(const GLValue& v) { return v.h; };
    679 
    680 template<class T>
    681 inline T getRandom (deRandom& rnd, T min, T max);
    682 
    683 template<>
    684 inline GLValue::Float getRandom (deRandom& rnd, GLValue::Float min, GLValue::Float max)
    685 {
    686 	if (max < min)
    687 		return min;
    688 
    689 	return GLValue::Float::create(min + deRandom_getFloat(&rnd) * (max.to<float>() - min.to<float>()));
    690 }
    691 
    692 template<>
    693 inline GLValue::Double getRandom (deRandom& rnd, GLValue::Double min, GLValue::Double max)
    694 {
    695 	if (max < min)
    696 		return min;
    697 
    698 	return GLValue::Double::create(min + deRandom_getFloat(&rnd) * (max.to<float>() - min.to<float>()));
    699 }
    700 
    701 template<>
    702 inline GLValue::Short getRandom (deRandom& rnd, GLValue::Short min, GLValue::Short max)
    703 {
    704 	if (max < min)
    705 		return min;
    706 
    707 	return GLValue::Short::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>()))));
    708 }
    709 
    710 template<>
    711 inline GLValue::Ushort getRandom (deRandom& rnd, GLValue::Ushort min, GLValue::Ushort max)
    712 {
    713 	if (max < min)
    714 		return min;
    715 
    716 	return GLValue::Ushort::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>()))));
    717 }
    718 
    719 template<>
    720 inline GLValue::Byte getRandom (deRandom& rnd, GLValue::Byte min, GLValue::Byte max)
    721 {
    722 	if (max < min)
    723 		return min;
    724 
    725 	return GLValue::Byte::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>()))));
    726 }
    727 
    728 template<>
    729 inline GLValue::Ubyte getRandom (deRandom& rnd, GLValue::Ubyte min, GLValue::Ubyte max)
    730 {
    731 	if (max < min)
    732 		return min;
    733 
    734 	return GLValue::Ubyte::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<int>() - min.to<int>()))));
    735 }
    736 
    737 template<>
    738 inline GLValue::Fixed getRandom (deRandom& rnd, GLValue::Fixed min, GLValue::Fixed max)
    739 {
    740 	if (max < min)
    741 		return min;
    742 
    743 	return GLValue::Fixed::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
    744 }
    745 
    746 template<>
    747 inline GLValue::Half getRandom (deRandom& rnd, GLValue::Half min, GLValue::Half max)
    748 {
    749 	if (max < min)
    750 		return min;
    751 
    752 	float fMax = max.to<float>();
    753 	float fMin = min.to<float>();
    754 	GLValue::Half h = GLValue::Half::create(fMin + deRandom_getFloat(&rnd) * (fMax - fMin));
    755 	return h;
    756 }
    757 
    758 template<>
    759 inline GLValue::Int getRandom (deRandom& rnd, GLValue::Int min, GLValue::Int max)
    760 {
    761 	if (max < min)
    762 		return min;
    763 
    764 	return GLValue::Int::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
    765 }
    766 
    767 template<>
    768 inline GLValue::Uint getRandom (deRandom& rnd, GLValue::Uint min, GLValue::Uint max)
    769 {
    770 	if (max < min)
    771 		return min;
    772 
    773 	return GLValue::Uint::create((min == max ? min : min + (deRandom_getUint32(&rnd) % (max.to<deUint32>() - min.to<deUint32>()))));
    774 }
    775 
    776 // Minimum difference required between coordinates
    777 template<class T>
    778 inline T minValue (void);
    779 
    780 template<>
    781 inline GLValue::Float minValue (void)
    782 {
    783 	return GLValue::Float::create(4 * 1.0f);
    784 }
    785 
    786 template<>
    787 inline GLValue::Double minValue (void)
    788 {
    789 	return GLValue::Double::create(4 * 1.0f);
    790 }
    791 
    792 template<>
    793 inline GLValue::Short minValue (void)
    794 {
    795 	return GLValue::Short::create(4 * 256);
    796 }
    797 
    798 template<>
    799 inline GLValue::Ushort minValue (void)
    800 {
    801 	return GLValue::Ushort::create(4 * 256);
    802 }
    803 
    804 template<>
    805 inline GLValue::Byte minValue (void)
    806 {
    807 	return GLValue::Byte::create(4 * 1);
    808 }
    809 
    810 template<>
    811 inline GLValue::Ubyte minValue (void)
    812 {
    813 	return GLValue::Ubyte::create(4 * 2);
    814 }
    815 
    816 template<>
    817 inline GLValue::Fixed minValue (void)
    818 {
    819 	return GLValue::Fixed::create(4 * 1);
    820 }
    821 
    822 template<>
    823 inline GLValue::Int minValue (void)
    824 {
    825 	return GLValue::Int::create(4 * 16777216);
    826 }
    827 
    828 template<>
    829 inline GLValue::Uint minValue (void)
    830 {
    831 	return GLValue::Uint::create(4 * 16777216);
    832 }
    833 
    834 template<>
    835 inline GLValue::Half minValue (void)
    836 {
    837 	return GLValue::Half::create(4 * 1.0f);
    838 }
    839 
    840 template<class T>
    841 inline T abs (T val);
    842 
    843 template<>
    844 inline GLValue::Fixed abs (GLValue::Fixed val)
    845 {
    846 	return GLValue::Fixed::create(0x7FFFu & val.getValue());
    847 }
    848 
    849 template<>
    850 inline GLValue::Ubyte abs (GLValue::Ubyte val)
    851 {
    852 	return val;
    853 }
    854 
    855 template<>
    856 inline GLValue::Byte abs (GLValue::Byte val)
    857 {
    858 	return GLValue::Byte::create(0x7Fu & val.getValue());
    859 }
    860 
    861 template<>
    862 inline GLValue::Ushort abs (GLValue::Ushort val)
    863 {
    864 	return val;
    865 }
    866 
    867 template<>
    868 inline GLValue::Short abs (GLValue::Short val)
    869 {
    870 	return GLValue::Short::create(0x7FFFu & val.getValue());
    871 }
    872 
    873 template<>
    874 inline GLValue::Float abs (GLValue::Float val)
    875 {
    876 	return GLValue::Float::create(std::fabs(val.to<float>()));
    877 }
    878 
    879 template<>
    880 inline GLValue::Double abs (GLValue::Double val)
    881 {
    882 	return GLValue::Double::create(std::fabs(val.to<float>()));
    883 }
    884 
    885 template<>
    886 inline GLValue::Uint abs (GLValue::Uint val)
    887 {
    888 	return val;
    889 }
    890 
    891 template<>
    892 inline GLValue::Int abs (GLValue::Int val)
    893 {
    894 	return GLValue::Int::create(0x7FFFFFFFu & val.getValue());
    895 }
    896 
    897 template<>
    898 inline GLValue::Half abs (GLValue::Half val)
    899 {
    900 	return GLValue::Half::create(std::fabs(val.to<float>()));
    901 }
    902 
    903 // AttriuteArray
    904 
    905 class AttributeArray
    906 {
    907 public:
    908 								AttributeArray		(DrawTestSpec::Storage storage, sglr::Context& context);
    909 								~AttributeArray		(void);
    910 
    911 	void						data				(DrawTestSpec::Target target, size_t size, const char* data, DrawTestSpec::Usage usage);
    912 	void						subdata				(DrawTestSpec::Target target, int offset, int size, const char* data);
    913 	void						setupArray			(bool bound, int offset, int size, DrawTestSpec::InputType inType, DrawTestSpec::OutputType outType, bool normalized, int stride, int instanceDivisor, const rr::GenericVec4& defaultAttrib, bool isPositionAttr, bool bgraComponentOrder);
    914 	void						bindAttribute		(deUint32 loc);
    915 	void						bindIndexArray		(DrawTestSpec::Target storage);
    916 
    917 	int							getComponentCount	(void) const { return m_componentCount; }
    918 	DrawTestSpec::Target		getTarget			(void) const { return m_target; }
    919 	DrawTestSpec::InputType		getInputType		(void) const { return m_inputType; }
    920 	DrawTestSpec::OutputType	getOutputType		(void) const { return m_outputType; }
    921 	DrawTestSpec::Storage		getStorageType		(void) const { return m_storage; }
    922 	bool						getNormalized		(void) const { return m_normalize; }
    923 	int							getStride			(void) const { return m_stride; }
    924 	bool						isBound				(void) const { return m_bound; }
    925 	bool						isPositionAttribute	(void) const { return m_isPositionAttr; }
    926 
    927 private:
    928 	DrawTestSpec::Storage		m_storage;
    929 	sglr::Context&				m_ctx;
    930 	deUint32					m_glBuffer;
    931 
    932 	int							m_size;
    933 	char*						m_data;
    934 	int							m_componentCount;
    935 	bool						m_bound;
    936 	DrawTestSpec::Target		m_target;
    937 	DrawTestSpec::InputType		m_inputType;
    938 	DrawTestSpec::OutputType	m_outputType;
    939 	bool						m_normalize;
    940 	int							m_stride;
    941 	int							m_offset;
    942 	rr::GenericVec4				m_defaultAttrib;
    943 	int							m_instanceDivisor;
    944 	bool						m_isPositionAttr;
    945 	bool						m_bgraOrder;
    946 };
    947 
    948 AttributeArray::AttributeArray (DrawTestSpec::Storage storage, sglr::Context& context)
    949 	: m_storage			(storage)
    950 	, m_ctx				(context)
    951 	, m_glBuffer		(0)
    952 	, m_size			(0)
    953 	, m_data			(DE_NULL)
    954 	, m_componentCount	(1)
    955 	, m_bound			(false)
    956 	, m_target			(DrawTestSpec::TARGET_ARRAY)
    957 	, m_inputType		(DrawTestSpec::INPUTTYPE_FLOAT)
    958 	, m_outputType		(DrawTestSpec::OUTPUTTYPE_VEC4)
    959 	, m_normalize		(false)
    960 	, m_stride			(0)
    961 	, m_offset			(0)
    962 	, m_instanceDivisor	(0)
    963 	, m_isPositionAttr	(false)
    964 	, m_bgraOrder		(false)
    965 {
    966 	if (m_storage == DrawTestSpec::STORAGE_BUFFER)
    967 	{
    968 		m_ctx.genBuffers(1, &m_glBuffer);
    969 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glGenBuffers()");
    970 	}
    971 }
    972 
    973 AttributeArray::~AttributeArray	(void)
    974 {
    975 	if (m_storage == DrawTestSpec::STORAGE_BUFFER)
    976 	{
    977 		m_ctx.deleteBuffers(1, &m_glBuffer);
    978 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDeleteBuffers()");
    979 	}
    980 	else if (m_storage == DrawTestSpec::STORAGE_USER)
    981 		delete[] m_data;
    982 	else
    983 		DE_ASSERT(false);
    984 }
    985 
    986 void AttributeArray::data (DrawTestSpec::Target target, size_t size, const char* ptr, DrawTestSpec::Usage usage)
    987 {
    988 	m_size = (int)size;
    989 	m_target = target;
    990 
    991 	if (m_storage == DrawTestSpec::STORAGE_BUFFER)
    992 	{
    993 		m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
    994 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
    995 
    996 		m_ctx.bufferData(targetToGL(target), size, ptr, usageToGL(usage));
    997 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferData()");
    998 	}
    999 	else if (m_storage == DrawTestSpec::STORAGE_USER)
   1000 	{
   1001 		if (m_data)
   1002 			delete[] m_data;
   1003 
   1004 		m_data = new char[size];
   1005 		std::memcpy(m_data, ptr, size);
   1006 	}
   1007 	else
   1008 		DE_ASSERT(false);
   1009 }
   1010 
   1011 void AttributeArray::subdata (DrawTestSpec::Target target, int offset, int size, const char* ptr)
   1012 {
   1013 	m_target = target;
   1014 
   1015 	if (m_storage == DrawTestSpec::STORAGE_BUFFER)
   1016 	{
   1017 		m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
   1018 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
   1019 
   1020 		m_ctx.bufferSubData(targetToGL(target), offset, size, ptr);
   1021 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferSubData()");
   1022 	}
   1023 	else if (m_storage == DrawTestSpec::STORAGE_USER)
   1024 		std::memcpy(m_data + offset, ptr, size);
   1025 	else
   1026 		DE_ASSERT(false);
   1027 }
   1028 
   1029 void AttributeArray::setupArray (bool bound, int offset, int size, DrawTestSpec::InputType inputType, DrawTestSpec::OutputType outType, bool normalized, int stride, int instanceDivisor, const rr::GenericVec4& defaultAttrib, bool isPositionAttr, bool bgraComponentOrder)
   1030 {
   1031 	m_componentCount	= size;
   1032 	m_bound				= bound;
   1033 	m_inputType			= inputType;
   1034 	m_outputType		= outType;
   1035 	m_normalize			= normalized;
   1036 	m_stride			= stride;
   1037 	m_offset			= offset;
   1038 	m_defaultAttrib		= defaultAttrib;
   1039 	m_instanceDivisor	= instanceDivisor;
   1040 	m_isPositionAttr	= isPositionAttr;
   1041 	m_bgraOrder			= bgraComponentOrder;
   1042 }
   1043 
   1044 void AttributeArray::bindAttribute (deUint32 loc)
   1045 {
   1046 	if (!isBound())
   1047 	{
   1048 		switch (m_inputType)
   1049 		{
   1050 			case DrawTestSpec::INPUTTYPE_FLOAT:
   1051 			{
   1052 				tcu::Vec4 attr = m_defaultAttrib.get<float>();
   1053 
   1054 				switch (m_componentCount)
   1055 				{
   1056 					case 1: m_ctx.vertexAttrib1f(loc, attr.x()); break;
   1057 					case 2: m_ctx.vertexAttrib2f(loc, attr.x(), attr.y()); break;
   1058 					case 3: m_ctx.vertexAttrib3f(loc, attr.x(), attr.y(), attr.z()); break;
   1059 					case 4: m_ctx.vertexAttrib4f(loc, attr.x(), attr.y(), attr.z(), attr.w()); break;
   1060 					default: DE_ASSERT(DE_FALSE); break;
   1061 				}
   1062 				break;
   1063 			}
   1064 			case DrawTestSpec::INPUTTYPE_INT:
   1065 			{
   1066 				tcu::IVec4 attr = m_defaultAttrib.get<deInt32>();
   1067 				m_ctx.vertexAttribI4i(loc, attr.x(), attr.y(), attr.z(), attr.w());
   1068 				break;
   1069 			}
   1070 			case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:
   1071 			{
   1072 				tcu::UVec4 attr = m_defaultAttrib.get<deUint32>();
   1073 				m_ctx.vertexAttribI4ui(loc, attr.x(), attr.y(), attr.z(), attr.w());
   1074 				break;
   1075 			}
   1076 			default:
   1077 				DE_ASSERT(DE_FALSE);
   1078 				break;
   1079 		}
   1080 	}
   1081 	else
   1082 	{
   1083 		const deUint8* basePtr = DE_NULL;
   1084 
   1085 		if (m_storage == DrawTestSpec::STORAGE_BUFFER)
   1086 		{
   1087 			m_ctx.bindBuffer(targetToGL(m_target), m_glBuffer);
   1088 			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
   1089 
   1090 			basePtr = DE_NULL;
   1091 		}
   1092 		else if (m_storage == DrawTestSpec::STORAGE_USER)
   1093 		{
   1094 			m_ctx.bindBuffer(targetToGL(m_target), 0);
   1095 			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
   1096 
   1097 			basePtr = (const deUint8*)m_data;
   1098 		}
   1099 		else
   1100 			DE_ASSERT(DE_FALSE);
   1101 
   1102 		if (!inputTypeIsFloatType(m_inputType))
   1103 		{
   1104 			// Input is not float type
   1105 
   1106 			if (outputTypeIsFloatType(m_outputType))
   1107 			{
   1108 				const int size = (m_bgraOrder) ? (GL_BGRA) : (m_componentCount);
   1109 
   1110 				DE_ASSERT(!(m_bgraOrder && m_componentCount != 4));
   1111 
   1112 				// Output type is float type
   1113 				m_ctx.vertexAttribPointer(loc, size, inputTypeToGL(m_inputType), m_normalize, m_stride, basePtr + m_offset);
   1114 				GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
   1115 			}
   1116 			else
   1117 			{
   1118 				// Output type is int type
   1119 				m_ctx.vertexAttribIPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_stride, basePtr + m_offset);
   1120 				GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribIPointer()");
   1121 			}
   1122 		}
   1123 		else
   1124 		{
   1125 			// Input type is float type
   1126 
   1127 			// Output type must be float type
   1128 			DE_ASSERT(outputTypeIsFloatType(m_outputType));
   1129 
   1130 			m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, basePtr + m_offset);
   1131 			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
   1132 		}
   1133 
   1134 		if (m_instanceDivisor)
   1135 			m_ctx.vertexAttribDivisor(loc, m_instanceDivisor);
   1136 	}
   1137 }
   1138 
   1139 void AttributeArray::bindIndexArray (DrawTestSpec::Target target)
   1140 {
   1141 	if (m_storage == DrawTestSpec::STORAGE_USER)
   1142 	{
   1143 	}
   1144 	else if (m_storage == DrawTestSpec::STORAGE_BUFFER)
   1145 	{
   1146 		m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
   1147 	}
   1148 }
   1149 
   1150 // DrawTestShaderProgram
   1151 
   1152 class DrawTestShaderProgram : public sglr::ShaderProgram
   1153 {
   1154 public:
   1155 												DrawTestShaderProgram		(const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays);
   1156 
   1157 	void										shadeVertices				(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
   1158 	void										shadeFragments				(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
   1159 
   1160 private:
   1161 	static std::string							genVertexSource				(const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays);
   1162 	static std::string							genFragmentSource			(const glu::RenderContext& ctx);
   1163 	static void									generateShaderParams		(std::map<std::string, std::string>& params, glu::ContextType type);
   1164 	static rr::GenericVecType					mapOutputType				(const DrawTestSpec::OutputType& type);
   1165 	static int									getComponentCount			(const DrawTestSpec::OutputType& type);
   1166 
   1167 	static sglr::pdec::ShaderProgramDeclaration createProgramDeclaration	(const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays);
   1168 
   1169 	std::vector<int>							m_componentCount;
   1170 	std::vector<bool>							m_isCoord;
   1171 	std::vector<rr::GenericVecType>				m_attrType;
   1172 };
   1173 
   1174 DrawTestShaderProgram::DrawTestShaderProgram (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays)
   1175 	: sglr::ShaderProgram	(createProgramDeclaration(ctx, arrays))
   1176 	, m_componentCount		(arrays.size())
   1177 	, m_isCoord				(arrays.size())
   1178 	, m_attrType			(arrays.size())
   1179 {
   1180 	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
   1181 	{
   1182 		m_componentCount[arrayNdx]	= getComponentCount(arrays[arrayNdx]->getOutputType());
   1183 		m_isCoord[arrayNdx]			= arrays[arrayNdx]->isPositionAttribute();
   1184 		m_attrType[arrayNdx]		= mapOutputType(arrays[arrayNdx]->getOutputType());
   1185 	}
   1186 }
   1187 
   1188 template <typename T>
   1189 void calcShaderColorCoord (tcu::Vec2& coord, tcu::Vec3& color, const tcu::Vector<T, 4>& attribValue, bool isCoordinate, int numComponents)
   1190 {
   1191 	if (isCoordinate)
   1192 		switch (numComponents)
   1193 		{
   1194 			case 1:	coord += tcu::Vec2((float)attribValue.x(),						(float)attribValue.x());					break;
   1195 			case 2:	coord += tcu::Vec2((float)attribValue.x(),						(float)attribValue.y());					break;
   1196 			case 3:	coord += tcu::Vec2((float)attribValue.x() + attribValue.z(),	(float)attribValue.y());					break;
   1197 			case 4:	coord += tcu::Vec2((float)attribValue.x() + attribValue.z(),	(float)attribValue.y() + attribValue.w());	break;
   1198 
   1199 			default:
   1200 				DE_ASSERT(false);
   1201 		}
   1202 	else
   1203 	{
   1204 		switch (numComponents)
   1205 		{
   1206 			case 1:
   1207 				color = color * (float)attribValue.x();
   1208 				break;
   1209 
   1210 			case 2:
   1211 				color.x() = color.x() * attribValue.x();
   1212 				color.y() = color.y() * attribValue.y();
   1213 				break;
   1214 
   1215 			case 3:
   1216 				color.x() = color.x() * attribValue.x();
   1217 				color.y() = color.y() * attribValue.y();
   1218 				color.z() = color.z() * attribValue.z();
   1219 				break;
   1220 
   1221 			case 4:
   1222 				color.x() = color.x() * attribValue.x() * attribValue.w();
   1223 				color.y() = color.y() * attribValue.y() * attribValue.w();
   1224 				color.z() = color.z() * attribValue.z() * attribValue.w();
   1225 				break;
   1226 
   1227 			default:
   1228 				DE_ASSERT(false);
   1229 		}
   1230 	}
   1231 }
   1232 
   1233 void DrawTestShaderProgram::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
   1234 {
   1235 	const float	u_coordScale = getUniformByName("u_coordScale").value.f;
   1236 	const float u_colorScale = getUniformByName("u_colorScale").value.f;
   1237 
   1238 	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
   1239 	{
   1240 		const size_t varyingLocColor = 0;
   1241 
   1242 		rr::VertexPacket& packet = *packets[packetNdx];
   1243 
   1244 		// Calc output color
   1245 		tcu::Vec2 coord = tcu::Vec2(0.0, 0.0);
   1246 		tcu::Vec3 color = tcu::Vec3(1.0, 1.0, 1.0);
   1247 
   1248 		for (int attribNdx = 0; attribNdx < (int)m_attrType.size(); attribNdx++)
   1249 		{
   1250 			const int	numComponents	= m_componentCount[attribNdx];
   1251 			const bool	isCoord			= m_isCoord[attribNdx];
   1252 
   1253 			switch (m_attrType[attribNdx])
   1254 			{
   1255 				case rr::GENERICVECTYPE_FLOAT:	calcShaderColorCoord(coord, color, rr::readVertexAttribFloat(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents);	break;
   1256 				case rr::GENERICVECTYPE_INT32:	calcShaderColorCoord(coord, color, rr::readVertexAttribInt	(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents);	break;
   1257 				case rr::GENERICVECTYPE_UINT32:	calcShaderColorCoord(coord, color, rr::readVertexAttribUint	(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents);	break;
   1258 				default:
   1259 					DE_ASSERT(false);
   1260 			}
   1261 		}
   1262 
   1263 		// Transform position
   1264 		{
   1265 			packet.position = tcu::Vec4(u_coordScale * coord.x(), u_coordScale * coord.y(), 1.0f, 1.0f);
   1266 			packet.pointSize = 1.0f;
   1267 		}
   1268 
   1269 		// Pass color to FS
   1270 		{
   1271 			packet.outputs[varyingLocColor] = tcu::Vec4(u_colorScale * color.x(), u_colorScale * color.y(), u_colorScale * color.z(), 1.0f) * 0.5f + tcu::Vec4(0.5f, 0.5f, 0.5f, 0.5f);
   1272 		}
   1273 	}
   1274 }
   1275 
   1276 void DrawTestShaderProgram::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
   1277 {
   1278 	const size_t varyingLocColor = 0;
   1279 
   1280 	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
   1281 	{
   1282 		rr::FragmentPacket& packet = packets[packetNdx];
   1283 
   1284 		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
   1285 			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packet, context, varyingLocColor, fragNdx));
   1286 	}
   1287 }
   1288 
   1289 std::string DrawTestShaderProgram::genVertexSource (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays)
   1290 {
   1291 	std::map<std::string, std::string>	params;
   1292 	std::stringstream					vertexShaderTmpl;
   1293 
   1294 	generateShaderParams(params, ctx.getType());
   1295 
   1296 	vertexShaderTmpl << "${VTX_HDR}";
   1297 
   1298 	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
   1299 	{
   1300 		vertexShaderTmpl
   1301 			<< "${VTX_IN} highp " << outputTypeToGLType(arrays[arrayNdx]->getOutputType()) << " a_" << arrayNdx << ";\n";
   1302 	}
   1303 
   1304 	vertexShaderTmpl <<
   1305 		"uniform highp float u_coordScale;\n"
   1306 		"uniform highp float u_colorScale;\n"
   1307 		"${VTX_OUT} ${COL_PRECISION} vec4 v_color;\n"
   1308 		"void main(void)\n"
   1309 		"{\n"
   1310 		"\tgl_PointSize = 1.0;\n"
   1311 		"\thighp vec2 coord = vec2(0.0, 0.0);\n"
   1312 		"\thighp vec3 color = vec3(1.0, 1.0, 1.0);\n";
   1313 
   1314 	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
   1315 	{
   1316 		const bool isPositionAttr = arrays[arrayNdx]->isPositionAttribute();
   1317 
   1318 		if (isPositionAttr)
   1319 		{
   1320 			switch (arrays[arrayNdx]->getOutputType())
   1321 			{
   1322 				case (DrawTestSpec::OUTPUTTYPE_FLOAT):
   1323 				case (DrawTestSpec::OUTPUTTYPE_INT):
   1324 				case (DrawTestSpec::OUTPUTTYPE_UINT):
   1325 					vertexShaderTmpl <<
   1326 						"\tcoord += vec2(float(a_" << arrayNdx << "), float(a_" << arrayNdx << "));\n";
   1327 					break;
   1328 
   1329 				case (DrawTestSpec::OUTPUTTYPE_VEC2):
   1330 				case (DrawTestSpec::OUTPUTTYPE_IVEC2):
   1331 				case (DrawTestSpec::OUTPUTTYPE_UVEC2):
   1332 					vertexShaderTmpl <<
   1333 						"\tcoord += vec2(a_" << arrayNdx << ".xy);\n";
   1334 					break;
   1335 
   1336 				case (DrawTestSpec::OUTPUTTYPE_VEC3):
   1337 				case (DrawTestSpec::OUTPUTTYPE_IVEC3):
   1338 				case (DrawTestSpec::OUTPUTTYPE_UVEC3):
   1339 					vertexShaderTmpl <<
   1340 						"\tcoord += vec2(a_" << arrayNdx << ".xy);\n"
   1341 						"\tcoord.x += float(a_" << arrayNdx << ".z);\n";
   1342 					break;
   1343 
   1344 				case (DrawTestSpec::OUTPUTTYPE_VEC4):
   1345 				case (DrawTestSpec::OUTPUTTYPE_IVEC4):
   1346 				case (DrawTestSpec::OUTPUTTYPE_UVEC4):
   1347 					vertexShaderTmpl <<
   1348 						"\tcoord += vec2(a_" << arrayNdx << ".xy);\n"
   1349 						"\tcoord += vec2(a_" << arrayNdx << ".zw);\n";
   1350 					break;
   1351 
   1352 				default:
   1353 					DE_ASSERT(false);
   1354 					break;
   1355 			}
   1356 		}
   1357 		else
   1358 		{
   1359 			switch (arrays[arrayNdx]->getOutputType())
   1360 			{
   1361 				case (DrawTestSpec::OUTPUTTYPE_FLOAT):
   1362 				case (DrawTestSpec::OUTPUTTYPE_INT):
   1363 				case (DrawTestSpec::OUTPUTTYPE_UINT):
   1364 					vertexShaderTmpl <<
   1365 						"\tcolor = color * float(a_" << arrayNdx << ");\n";
   1366 					break;
   1367 
   1368 				case (DrawTestSpec::OUTPUTTYPE_VEC2):
   1369 				case (DrawTestSpec::OUTPUTTYPE_IVEC2):
   1370 				case (DrawTestSpec::OUTPUTTYPE_UVEC2):
   1371 					vertexShaderTmpl <<
   1372 						"\tcolor.rg = color.rg * vec2(a_" << arrayNdx << ".xy);\n";
   1373 					break;
   1374 
   1375 				case (DrawTestSpec::OUTPUTTYPE_VEC3):
   1376 				case (DrawTestSpec::OUTPUTTYPE_IVEC3):
   1377 				case (DrawTestSpec::OUTPUTTYPE_UVEC3):
   1378 					vertexShaderTmpl <<
   1379 						"\tcolor = color.rgb * vec3(a_" << arrayNdx << ".xyz);\n";
   1380 					break;
   1381 
   1382 				case (DrawTestSpec::OUTPUTTYPE_VEC4):
   1383 				case (DrawTestSpec::OUTPUTTYPE_IVEC4):
   1384 				case (DrawTestSpec::OUTPUTTYPE_UVEC4):
   1385 					vertexShaderTmpl <<
   1386 						"\tcolor = color.rgb * vec3(a_" << arrayNdx << ".xyz) * float(a_" << arrayNdx << ".w);\n";
   1387 					break;
   1388 
   1389 				default:
   1390 					DE_ASSERT(false);
   1391 					break;
   1392 			}
   1393 		}
   1394 	}
   1395 
   1396 	vertexShaderTmpl <<
   1397 		"\tv_color = vec4(u_colorScale * color, 1.0) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5);\n"
   1398 		"\tgl_Position = vec4(u_coordScale * coord, 1.0, 1.0);\n"
   1399 		"}\n";
   1400 
   1401 	return tcu::StringTemplate(vertexShaderTmpl.str().c_str()).specialize(params);
   1402 }
   1403 
   1404 std::string DrawTestShaderProgram::genFragmentSource (const glu::RenderContext& ctx)
   1405 {
   1406 	std::map<std::string, std::string> params;
   1407 
   1408 	generateShaderParams(params, ctx.getType());
   1409 
   1410 	static const char* fragmentShaderTmpl =
   1411 		"${FRAG_HDR}"
   1412 		"${FRAG_IN} ${COL_PRECISION} vec4 v_color;\n"
   1413 		"void main(void)\n"
   1414 		"{\n"
   1415 		"\t${FRAG_COLOR} = v_color;\n"
   1416 		"}\n";
   1417 
   1418 	return tcu::StringTemplate(fragmentShaderTmpl).specialize(params);
   1419 }
   1420 
   1421 void DrawTestShaderProgram::generateShaderParams (std::map<std::string, std::string>& params, glu::ContextType type)
   1422 {
   1423 	if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_300_ES))
   1424 	{
   1425 		params["VTX_IN"]		= "in";
   1426 		params["VTX_OUT"]		= "out";
   1427 		params["FRAG_IN"]		= "in";
   1428 		params["FRAG_COLOR"]	= "dEQP_FragColor";
   1429 		params["VTX_HDR"]		= "#version 300 es\n";
   1430 		params["FRAG_HDR"]		= "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
   1431 		params["COL_PRECISION"]	= "mediump";
   1432 	}
   1433 	else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_100_ES))
   1434 	{
   1435 		params["VTX_IN"]		= "attribute";
   1436 		params["VTX_OUT"]		= "varying";
   1437 		params["FRAG_IN"]		= "varying";
   1438 		params["FRAG_COLOR"]	= "gl_FragColor";
   1439 		params["VTX_HDR"]		= "";
   1440 		params["FRAG_HDR"]		= "";
   1441 		params["COL_PRECISION"]	= "mediump";
   1442 	}
   1443 	else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_430))
   1444 	{
   1445 		params["VTX_IN"]		= "in";
   1446 		params["VTX_OUT"]		= "out";
   1447 		params["FRAG_IN"]		= "in";
   1448 		params["FRAG_COLOR"]	= "dEQP_FragColor";
   1449 		params["VTX_HDR"]		= "#version 430\n";
   1450 		params["FRAG_HDR"]		= "#version 430\nlayout(location = 0) out highp vec4 dEQP_FragColor;\n";
   1451 		params["COL_PRECISION"]	= "highp";
   1452 	}
   1453 	else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_330))
   1454 	{
   1455 		params["VTX_IN"]		= "in";
   1456 		params["VTX_OUT"]		= "out";
   1457 		params["FRAG_IN"]		= "in";
   1458 		params["FRAG_COLOR"]	= "dEQP_FragColor";
   1459 		params["VTX_HDR"]		= "#version 330\n";
   1460 		params["FRAG_HDR"]		= "#version 330\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
   1461 		params["COL_PRECISION"]	= "mediump";
   1462 	}
   1463 	else
   1464 		DE_ASSERT(DE_FALSE);
   1465 }
   1466 
   1467 rr::GenericVecType DrawTestShaderProgram::mapOutputType (const DrawTestSpec::OutputType& type)
   1468 {
   1469 	switch (type)
   1470 	{
   1471 		case (DrawTestSpec::OUTPUTTYPE_FLOAT):
   1472 		case (DrawTestSpec::OUTPUTTYPE_VEC2):
   1473 		case (DrawTestSpec::OUTPUTTYPE_VEC3):
   1474 		case (DrawTestSpec::OUTPUTTYPE_VEC4):
   1475 			return rr::GENERICVECTYPE_FLOAT;
   1476 
   1477 		case (DrawTestSpec::OUTPUTTYPE_INT):
   1478 		case (DrawTestSpec::OUTPUTTYPE_IVEC2):
   1479 		case (DrawTestSpec::OUTPUTTYPE_IVEC3):
   1480 		case (DrawTestSpec::OUTPUTTYPE_IVEC4):
   1481 			return rr::GENERICVECTYPE_INT32;
   1482 
   1483 		case (DrawTestSpec::OUTPUTTYPE_UINT):
   1484 		case (DrawTestSpec::OUTPUTTYPE_UVEC2):
   1485 		case (DrawTestSpec::OUTPUTTYPE_UVEC3):
   1486 		case (DrawTestSpec::OUTPUTTYPE_UVEC4):
   1487 			return rr::GENERICVECTYPE_UINT32;
   1488 
   1489 		default:
   1490 			DE_ASSERT(false);
   1491 			return rr::GENERICVECTYPE_LAST;
   1492 	}
   1493 }
   1494 
   1495 int DrawTestShaderProgram::getComponentCount (const DrawTestSpec::OutputType& type)
   1496 {
   1497 	switch (type)
   1498 	{
   1499 		case (DrawTestSpec::OUTPUTTYPE_FLOAT):
   1500 		case (DrawTestSpec::OUTPUTTYPE_INT):
   1501 		case (DrawTestSpec::OUTPUTTYPE_UINT):
   1502 			return 1;
   1503 
   1504 		case (DrawTestSpec::OUTPUTTYPE_VEC2):
   1505 		case (DrawTestSpec::OUTPUTTYPE_IVEC2):
   1506 		case (DrawTestSpec::OUTPUTTYPE_UVEC2):
   1507 			return 2;
   1508 
   1509 		case (DrawTestSpec::OUTPUTTYPE_VEC3):
   1510 		case (DrawTestSpec::OUTPUTTYPE_IVEC3):
   1511 		case (DrawTestSpec::OUTPUTTYPE_UVEC3):
   1512 			return 3;
   1513 
   1514 		case (DrawTestSpec::OUTPUTTYPE_VEC4):
   1515 		case (DrawTestSpec::OUTPUTTYPE_IVEC4):
   1516 		case (DrawTestSpec::OUTPUTTYPE_UVEC4):
   1517 			return 4;
   1518 
   1519 		default:
   1520 			DE_ASSERT(false);
   1521 			return 0;
   1522 	}
   1523 }
   1524 
   1525 sglr::pdec::ShaderProgramDeclaration DrawTestShaderProgram::createProgramDeclaration (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays)
   1526 {
   1527 	sglr::pdec::ShaderProgramDeclaration decl;
   1528 
   1529 	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
   1530 		decl << sglr::pdec::VertexAttribute(std::string("a_") + de::toString(arrayNdx), mapOutputType(arrays[arrayNdx]->getOutputType()));
   1531 
   1532 	decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
   1533 	decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT);
   1534 
   1535 	decl << sglr::pdec::VertexSource(genVertexSource(ctx, arrays));
   1536 	decl << sglr::pdec::FragmentSource(genFragmentSource(ctx));
   1537 
   1538 	decl << sglr::pdec::Uniform("u_coordScale", glu::TYPE_FLOAT);
   1539 	decl << sglr::pdec::Uniform("u_colorScale", glu::TYPE_FLOAT);
   1540 
   1541 	return decl;
   1542 }
   1543 
   1544 class RandomArrayGenerator
   1545 {
   1546 public:
   1547 	static char*			generateArray			(int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type);
   1548 	static char*			generateIndices			(int seed, int elementCount, DrawTestSpec::IndexType type, int offset, int min, int max, int indexBase);
   1549 	static rr::GenericVec4	generateAttributeValue	(int seed, DrawTestSpec::InputType type);
   1550 
   1551 private:
   1552 	template<typename T>
   1553 	static char*			createIndices			(int seed, int elementCount, int offset, int min, int max, int indexBase);
   1554 	static void				setData					(char* data, DrawTestSpec::InputType type, deRandom& rnd, GLValue min, GLValue max);
   1555 
   1556 	static char*			generateBasicArray		(int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type);
   1557 	template<typename T, typename GLType>
   1558 	static char*			createBasicArray		(int seed, int elementCount, int componentCount, int offset, int stride);
   1559 	static char*			generatePackedArray		(int seed, int elementCount, int componentCount, int offset, int stride);
   1560 };
   1561 
   1562 void RandomArrayGenerator::setData (char* data, DrawTestSpec::InputType type, deRandom& rnd, GLValue min, GLValue max)
   1563 {
   1564 	switch (type)
   1565 	{
   1566 		case DrawTestSpec::INPUTTYPE_FLOAT:
   1567 		{
   1568 			alignmentSafeAssignment<float>(data, getRandom<GLValue::Float>(rnd, min.fl, max.fl));
   1569 			break;
   1570 		}
   1571 
   1572 		case DrawTestSpec::INPUTTYPE_SHORT:
   1573 		{
   1574 			alignmentSafeAssignment<deInt16>(data, getRandom<GLValue::Short>(rnd, min.s, max.s));
   1575 			break;
   1576 		}
   1577 
   1578 		case DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT:
   1579 		{
   1580 			alignmentSafeAssignment<deUint16>(data, getRandom<GLValue::Ushort>(rnd, min.us, max.us));
   1581 			break;
   1582 		}
   1583 
   1584 		case DrawTestSpec::INPUTTYPE_BYTE:
   1585 		{
   1586 			alignmentSafeAssignment<deInt8>(data, getRandom<GLValue::Byte>(rnd, min.b, max.b));
   1587 			break;
   1588 		}
   1589 
   1590 		case DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE:
   1591 		{
   1592 			alignmentSafeAssignment<deUint8>(data, getRandom<GLValue::Ubyte>(rnd, min.ub, max.ub));
   1593 			break;
   1594 		}
   1595 
   1596 		case DrawTestSpec::INPUTTYPE_FIXED:
   1597 		{
   1598 			alignmentSafeAssignment<deInt32>(data, getRandom<GLValue::Fixed>(rnd, min.fi, max.fi));
   1599 			break;
   1600 		}
   1601 
   1602 		case DrawTestSpec::INPUTTYPE_INT:
   1603 		{
   1604 			alignmentSafeAssignment<deInt32>(data, getRandom<GLValue::Int>(rnd, min.i, max.i));
   1605 			break;
   1606 		}
   1607 
   1608 		case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:
   1609 		{
   1610 			alignmentSafeAssignment<deUint32>(data, getRandom<GLValue::Uint>(rnd, min.ui, max.ui));
   1611 			break;
   1612 		}
   1613 
   1614 		case DrawTestSpec::INPUTTYPE_HALF:
   1615 		{
   1616 			alignmentSafeAssignment<deFloat16>(data, getRandom<GLValue::Half>(rnd, min.h, max.h).getValue());
   1617 			break;
   1618 		}
   1619 
   1620 		default:
   1621 			DE_ASSERT(false);
   1622 			break;
   1623 	}
   1624 }
   1625 
   1626 char* RandomArrayGenerator::generateArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type)
   1627 {
   1628 	if (type == DrawTestSpec::INPUTTYPE_INT_2_10_10_10 || type == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
   1629 		return generatePackedArray(seed, elementCount, componentCount, offset, stride);
   1630 	else
   1631 		return generateBasicArray(seed, elementCount, componentCount, offset, stride, type);
   1632 }
   1633 
   1634 char* RandomArrayGenerator::generateBasicArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type)
   1635 {
   1636 	switch (type)
   1637 	{
   1638 		case DrawTestSpec::INPUTTYPE_FLOAT:				return createBasicArray<float,		GLValue::Float>	(seed, elementCount, componentCount, offset, stride);
   1639 		case DrawTestSpec::INPUTTYPE_DOUBLE:			return createBasicArray<double,		GLValue::Double>(seed, elementCount, componentCount, offset, stride);
   1640 		case DrawTestSpec::INPUTTYPE_SHORT:				return createBasicArray<deInt16,	GLValue::Short>	(seed, elementCount, componentCount, offset, stride);
   1641 		case DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT:	return createBasicArray<deUint16,	GLValue::Ushort>(seed, elementCount, componentCount, offset, stride);
   1642 		case DrawTestSpec::INPUTTYPE_BYTE:				return createBasicArray<deInt8,		GLValue::Byte>	(seed, elementCount, componentCount, offset, stride);
   1643 		case DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE:		return createBasicArray<deUint8,	GLValue::Ubyte>	(seed, elementCount, componentCount, offset, stride);
   1644 		case DrawTestSpec::INPUTTYPE_FIXED:				return createBasicArray<deInt32,	GLValue::Fixed>	(seed, elementCount, componentCount, offset, stride);
   1645 		case DrawTestSpec::INPUTTYPE_INT:				return createBasicArray<deInt32,	GLValue::Int>	(seed, elementCount, componentCount, offset, stride);
   1646 		case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:		return createBasicArray<deUint32,	GLValue::Uint>	(seed, elementCount, componentCount, offset, stride);
   1647 		case DrawTestSpec::INPUTTYPE_HALF:				return createBasicArray<deFloat16,	GLValue::Half>	(seed, elementCount, componentCount, offset, stride);
   1648 		default:
   1649 			DE_ASSERT(false);
   1650 			break;
   1651 	}
   1652 	return DE_NULL;
   1653 }
   1654 
   1655 template<typename T, typename GLType>
   1656 char* RandomArrayGenerator::createBasicArray (int seed, int elementCount, int componentCount, int offset, int stride)
   1657 {
   1658 	DE_ASSERT(componentCount >= 1 && componentCount <= 4);
   1659 
   1660 	const GLType min = extractGLValue<GLType>(GLValue::getMinValue(GLValueTypeTraits<GLType>::Type));
   1661 	const GLType max = extractGLValue<GLType>(GLValue::getMaxValue(GLValueTypeTraits<GLType>::Type));
   1662 
   1663 	const size_t componentSize	= sizeof(T);
   1664 	const size_t elementSize	= componentSize * componentCount;
   1665 	const size_t bufferSize		= offset + (elementCount - 1) * stride + elementSize;
   1666 
   1667 	char* data = new char[bufferSize];
   1668 	char* writePtr = data + offset;
   1669 
   1670 	GLType previousComponents[4];
   1671 
   1672 	deRandom rnd;
   1673 	deRandom_init(&rnd, seed);
   1674 
   1675 	for (int vertexNdx = 0; vertexNdx < elementCount; vertexNdx++)
   1676 	{
   1677 		GLType components[4];
   1678 
   1679 		for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
   1680 		{
   1681 			components[componentNdx] = getRandom<GLType>(rnd, min, max);
   1682 
   1683 			// Try to not create vertex near previous
   1684 			if (vertexNdx != 0 && abs(components[componentNdx] - previousComponents[componentNdx]) < minValue<GLType>())
   1685 			{
   1686 				// Too close, try again (but only once)
   1687 				components[componentNdx] = getRandom<GLType>(rnd, min, max);
   1688 			}
   1689 		}
   1690 
   1691 		for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
   1692 			previousComponents[componentNdx] = components[componentNdx];
   1693 
   1694 		for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
   1695 			alignmentSafeAssignment(writePtr + componentNdx*componentSize, components[componentNdx].getValue());
   1696 
   1697 		writePtr += stride;
   1698 	}
   1699 
   1700 	return data;
   1701 }
   1702 
   1703 char* RandomArrayGenerator::generatePackedArray (int seed, int elementCount, int componentCount, int offset, int stride)
   1704 {
   1705 	DE_ASSERT(componentCount == 4);
   1706 	DE_UNREF(componentCount);
   1707 
   1708 	const deUint32 limit10		= (1 << 10);
   1709 	const deUint32 limit2		= (1 << 2);
   1710 	const size_t elementSize	= 4;
   1711 	const size_t bufferSize		= offset + (elementCount - 1) * stride + elementSize;
   1712 
   1713 	char* data = new char[bufferSize];
   1714 	char* writePtr = data + offset;
   1715 
   1716 	deRandom rnd;
   1717 	deRandom_init(&rnd, seed);
   1718 
   1719 	for (int vertexNdx = 0; vertexNdx < elementCount; vertexNdx++)
   1720 	{
   1721 		const deUint32 x			= deRandom_getUint32(&rnd) % limit10;
   1722 		const deUint32 y			= deRandom_getUint32(&rnd) % limit10;
   1723 		const deUint32 z			= deRandom_getUint32(&rnd) % limit10;
   1724 		const deUint32 w			= deRandom_getUint32(&rnd) % limit2;
   1725 		const deUint32 packedValue	= (w << 30) | (z << 20) | (y << 10) | (x);
   1726 
   1727 		alignmentSafeAssignment(writePtr, packedValue);
   1728 		writePtr += stride;
   1729 	}
   1730 
   1731 	return data;
   1732 }
   1733 
   1734 char* RandomArrayGenerator::generateIndices (int seed, int elementCount, DrawTestSpec::IndexType type, int offset, int min, int max, int indexBase)
   1735 {
   1736 	char* data = DE_NULL;
   1737 
   1738 	switch (type)
   1739 	{
   1740 		case DrawTestSpec::INDEXTYPE_BYTE:
   1741 			data = createIndices<deUint8>(seed, elementCount, offset, min, max, indexBase);
   1742 			break;
   1743 
   1744 		case DrawTestSpec::INDEXTYPE_SHORT:
   1745 			data = createIndices<deUint16>(seed, elementCount, offset, min, max, indexBase);
   1746 			break;
   1747 
   1748 		case DrawTestSpec::INDEXTYPE_INT:
   1749 			data = createIndices<deUint32>(seed, elementCount, offset, min, max, indexBase);
   1750 			break;
   1751 
   1752 		default:
   1753 			DE_ASSERT(false);
   1754 			break;
   1755 	}
   1756 
   1757 	return data;
   1758 }
   1759 
   1760 template<typename T>
   1761 char* RandomArrayGenerator::createIndices (int seed, int elementCount, int offset, int min, int max, int indexBase)
   1762 {
   1763 	const size_t elementSize	= sizeof(T);
   1764 	const size_t bufferSize		= offset + elementCount * elementSize;
   1765 
   1766 	char* data = new char[bufferSize];
   1767 	char* writePtr = data + offset;
   1768 
   1769 	deUint32 oldNdx1 = deUint32(-1);
   1770 	deUint32 oldNdx2 = deUint32(-1);
   1771 
   1772 	deRandom rnd;
   1773 	deRandom_init(&rnd, seed);
   1774 
   1775 	DE_ASSERT(indexBase >= 0); // watch for underflows
   1776 
   1777 	if (min < 0 || (size_t)min > std::numeric_limits<T>::max() ||
   1778 		max < 0 || (size_t)max > std::numeric_limits<T>::max() ||
   1779 		min > max)
   1780 		DE_ASSERT(!"Invalid range");
   1781 
   1782 	for (int elementNdx = 0; elementNdx < elementCount; ++elementNdx)
   1783 	{
   1784 		deUint32 ndx = getRandom(rnd, GLValue::Uint::create(min), GLValue::Uint::create(max)).getValue();
   1785 
   1786 		// Try not to generate same index as any of previous two. This prevents
   1787 		// generation of degenerate triangles and lines. If [min, max] is too
   1788 		// small this cannot be guaranteed.
   1789 
   1790 		if (ndx == oldNdx1)			++ndx;
   1791 		if (ndx > (deUint32)max)	ndx = min;
   1792 		if (ndx == oldNdx2)			++ndx;
   1793 		if (ndx > (deUint32)max)	ndx = min;
   1794 		if (ndx == oldNdx1)			++ndx;
   1795 		if (ndx > (deUint32)max)	ndx = min;
   1796 
   1797 		oldNdx2 = oldNdx1;
   1798 		oldNdx1 = ndx;
   1799 
   1800 		ndx += indexBase;
   1801 
   1802 		alignmentSafeAssignment<T>(writePtr + elementSize * elementNdx, T(ndx));
   1803 	}
   1804 
   1805 	return data;
   1806 }
   1807 
   1808 rr::GenericVec4	RandomArrayGenerator::generateAttributeValue (int seed, DrawTestSpec::InputType type)
   1809 {
   1810 	de::Random random(seed);
   1811 
   1812 	switch (type)
   1813 	{
   1814 		case DrawTestSpec::INPUTTYPE_FLOAT:
   1815 			return rr::GenericVec4(generateRandomVec4(random));
   1816 
   1817 		case DrawTestSpec::INPUTTYPE_INT:
   1818 			return rr::GenericVec4(generateRandomIVec4(random));
   1819 
   1820 		case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:
   1821 			return rr::GenericVec4(generateRandomUVec4(random));
   1822 
   1823 		default:
   1824 			DE_ASSERT(false);
   1825 			return rr::GenericVec4(tcu::Vec4(1, 1, 1, 1));
   1826 	}
   1827 }
   1828 
   1829 } // anonymous
   1830 
   1831 // AttributePack
   1832 
   1833 class AttributePack
   1834 {
   1835 public:
   1836 
   1837 								AttributePack		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, sglr::Context& drawContext, const tcu::UVec2& screenSize, bool useVao, bool logEnabled);
   1838 								~AttributePack		(void);
   1839 
   1840 	AttributeArray*				getArray			(int i);
   1841 	int							getArrayCount		(void);
   1842 
   1843 	void						newArray			(DrawTestSpec::Storage storage);
   1844 	void						clearArrays			(void);
   1845 	void 						updateProgram		(void);
   1846 
   1847 	void						render 				(DrawTestSpec::Primitive primitive, DrawTestSpec::DrawMethod drawMethod, int firstVertex, int vertexCount, DrawTestSpec::IndexType indexType, const void* indexOffset, int rangeStart, int rangeEnd, int instanceCount, int indirectOffset, int baseVertex, float coordScale, float colorScale, AttributeArray* indexArray);
   1848 
   1849 	const tcu::Surface&			getSurface			(void) const { return m_screen; }
   1850 private:
   1851 	tcu::TestContext&			m_testCtx;
   1852 	glu::RenderContext&			m_renderCtx;
   1853 	sglr::Context&				m_ctx;
   1854 
   1855 	std::vector<AttributeArray*>m_arrays;
   1856 	sglr::ShaderProgram*		m_program;
   1857 	tcu::Surface				m_screen;
   1858 	const bool					m_useVao;
   1859 	const bool					m_logEnabled;
   1860 	deUint32					m_programID;
   1861 	deUint32					m_vaoID;
   1862 };
   1863 
   1864 AttributePack::AttributePack (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, sglr::Context& drawContext, const tcu::UVec2& screenSize, bool useVao, bool logEnabled)
   1865 	: m_testCtx		(testCtx)
   1866 	, m_renderCtx	(renderCtx)
   1867 	, m_ctx			(drawContext)
   1868 	, m_program		(DE_NULL)
   1869 	, m_screen		(screenSize.x(), screenSize.y())
   1870 	, m_useVao		(useVao)
   1871 	, m_logEnabled	(logEnabled)
   1872 	, m_programID	(0)
   1873 	, m_vaoID		(0)
   1874 {
   1875 	if (m_useVao)
   1876 		m_ctx.genVertexArrays(1, &m_vaoID);
   1877 }
   1878 
   1879 AttributePack::~AttributePack (void)
   1880 {
   1881 	clearArrays();
   1882 
   1883 	if (m_programID)
   1884 		m_ctx.deleteProgram(m_programID);
   1885 
   1886 	if (m_program)
   1887 		delete m_program;
   1888 
   1889 	if (m_useVao)
   1890 		m_ctx.deleteVertexArrays(1, &m_vaoID);
   1891 }
   1892 
   1893 AttributeArray* AttributePack::getArray (int i)
   1894 {
   1895 	return m_arrays.at(i);
   1896 }
   1897 
   1898 int AttributePack::getArrayCount (void)
   1899 {
   1900 	return (int)m_arrays.size();
   1901 }
   1902 
   1903 void AttributePack::newArray (DrawTestSpec::Storage storage)
   1904 {
   1905 	m_arrays.push_back(new AttributeArray(storage, m_ctx));
   1906 }
   1907 
   1908 void AttributePack::clearArrays (void)
   1909 {
   1910 	for (std::vector<AttributeArray*>::iterator itr = m_arrays.begin(); itr != m_arrays.end(); itr++)
   1911 		delete *itr;
   1912 	m_arrays.clear();
   1913 }
   1914 
   1915 void AttributePack::updateProgram (void)
   1916 {
   1917 	if (m_programID)
   1918 		m_ctx.deleteProgram(m_programID);
   1919 	if (m_program)
   1920 		delete m_program;
   1921 
   1922 	m_program = new DrawTestShaderProgram(m_renderCtx, m_arrays);
   1923 	m_programID = m_ctx.createProgram(m_program);
   1924 }
   1925 
   1926 void AttributePack::render (DrawTestSpec::Primitive primitive, DrawTestSpec::DrawMethod drawMethod, int firstVertex, int vertexCount, DrawTestSpec::IndexType indexType, const void* indexOffset, int rangeStart, int rangeEnd, int instanceCount, int indirectOffset, int baseVertex, float coordScale, float colorScale, AttributeArray* indexArray)
   1927 {
   1928 	DE_ASSERT(m_program != DE_NULL);
   1929 	DE_ASSERT(m_programID != 0);
   1930 
   1931 	m_ctx.viewport(0, 0, m_screen.getWidth(), m_screen.getHeight());
   1932 	m_ctx.clearColor(0.0, 0.0, 0.0, 1.0);
   1933 	m_ctx.clear(GL_COLOR_BUFFER_BIT);
   1934 
   1935 	m_ctx.useProgram(m_programID);
   1936 	GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glUseProgram()");
   1937 
   1938 	m_ctx.uniform1f(m_ctx.getUniformLocation(m_programID, "u_coordScale"), coordScale);
   1939 	m_ctx.uniform1f(m_ctx.getUniformLocation(m_programID, "u_colorScale"), colorScale);
   1940 
   1941 	if (m_useVao)
   1942 		m_ctx.bindVertexArray(m_vaoID);
   1943 
   1944 	if (indexArray)
   1945 		indexArray->bindIndexArray(DrawTestSpec::TARGET_ELEMENT_ARRAY);
   1946 
   1947 	for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
   1948 	{
   1949 		std::stringstream attribName;
   1950 		attribName << "a_" << arrayNdx;
   1951 
   1952 		deUint32 loc = m_ctx.getAttribLocation(m_programID, attribName.str().c_str());
   1953 
   1954 		if (m_arrays[arrayNdx]->isBound())
   1955 		{
   1956 			m_ctx.enableVertexAttribArray(loc);
   1957 			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glEnableVertexAttribArray()");
   1958 		}
   1959 
   1960 		m_arrays[arrayNdx]->bindAttribute(loc);
   1961 	}
   1962 
   1963 	if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS)
   1964 	{
   1965 		m_ctx.drawArrays(primitiveToGL(primitive), firstVertex, vertexCount);
   1966 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArrays()");
   1967 	}
   1968 	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED)
   1969 	{
   1970 		m_ctx.drawArraysInstanced(primitiveToGL(primitive), firstVertex, vertexCount, instanceCount);
   1971 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysInstanced()");
   1972 	}
   1973 	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS)
   1974 	{
   1975 		m_ctx.drawElements(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset);
   1976 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElements()");
   1977 	}
   1978 	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED)
   1979 	{
   1980 		m_ctx.drawRangeElements(primitiveToGL(primitive), rangeStart, rangeEnd, vertexCount, indexTypeToGL(indexType), indexOffset);
   1981 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawRangeElements()");
   1982 	}
   1983 	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED)
   1984 	{
   1985 		m_ctx.drawElementsInstanced(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, instanceCount);
   1986 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsInstanced()");
   1987 	}
   1988 	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT)
   1989 	{
   1990 		struct DrawCommand
   1991 		{
   1992 			GLuint count;
   1993 			GLuint primCount;
   1994 			GLuint first;
   1995 			GLuint reservedMustBeZero;
   1996 		};
   1997 		deUint8* buffer = new deUint8[sizeof(DrawCommand) + indirectOffset];
   1998 
   1999 		{
   2000 			DrawCommand command;
   2001 
   2002 			command.count				= vertexCount;
   2003 			command.primCount			= instanceCount;
   2004 			command.first				= firstVertex;
   2005 			command.reservedMustBeZero	= 0;
   2006 
   2007 			memcpy(buffer + indirectOffset, &command, sizeof(command));
   2008 
   2009 			if (m_logEnabled)
   2010 				m_testCtx.getLog()
   2011 					<< tcu::TestLog::Message
   2012 					<< "DrawArraysIndirectCommand:\n"
   2013 					<< "\tcount: " << command.count << "\n"
   2014 					<< "\tprimCount: " << command.primCount << "\n"
   2015 					<< "\tfirst: " << command.first << "\n"
   2016 					<< "\treservedMustBeZero: " << command.reservedMustBeZero << "\n"
   2017 					<< tcu::TestLog::EndMessage;
   2018 		}
   2019 
   2020 		GLuint indirectBuf = 0;
   2021 		m_ctx.genBuffers(1, &indirectBuf);
   2022 		m_ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf);
   2023 		m_ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand) + indirectOffset, buffer, GL_STATIC_DRAW);
   2024 		delete [] buffer;
   2025 
   2026 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "Setup draw indirect buffer");
   2027 
   2028 		m_ctx.drawArraysIndirect(primitiveToGL(primitive), (const deInt8*)DE_NULL + indirectOffset);
   2029 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysIndirect()");
   2030 
   2031 		m_ctx.deleteBuffers(1, &indirectBuf);
   2032 	}
   2033 	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT)
   2034 	{
   2035 		struct DrawCommand
   2036 		{
   2037 			GLuint count;
   2038 			GLuint primCount;
   2039 			GLuint firstIndex;
   2040 			GLint  baseVertex;
   2041 			GLuint reservedMustBeZero;
   2042 		};
   2043 		deUint8* buffer = new deUint8[sizeof(DrawCommand) + indirectOffset];
   2044 
   2045 		{
   2046 			DrawCommand command;
   2047 
   2048 			// index offset must be converted to firstIndex by dividing with the index element size
   2049 			DE_ASSERT(((const deUint8*)indexOffset - (const deUint8*)DE_NULL) % gls::DrawTestSpec::indexTypeSize(indexType) == 0); // \note This is checked in spec validation
   2050 
   2051 			command.count				= vertexCount;
   2052 			command.primCount			= instanceCount;
   2053 			command.firstIndex			= (glw::GLuint)(((const deUint8*)indexOffset - (const deUint8*)DE_NULL) / gls::DrawTestSpec::indexTypeSize(indexType));
   2054 			command.baseVertex			= baseVertex;
   2055 			command.reservedMustBeZero	= 0;
   2056 
   2057 			memcpy(buffer + indirectOffset, &command, sizeof(command));
   2058 
   2059 			if (m_logEnabled)
   2060 				m_testCtx.getLog()
   2061 					<< tcu::TestLog::Message
   2062 					<< "DrawElementsIndirectCommand:\n"
   2063 					<< "\tcount: " << command.count << "\n"
   2064 					<< "\tprimCount: " << command.primCount << "\n"
   2065 					<< "\tfirstIndex: " << command.firstIndex << "\n"
   2066 					<< "\tbaseVertex: " << command.baseVertex << "\n"
   2067 					<< "\treservedMustBeZero: " << command.reservedMustBeZero << "\n"
   2068 					<< tcu::TestLog::EndMessage;
   2069 		}
   2070 
   2071 		GLuint indirectBuf = 0;
   2072 		m_ctx.genBuffers(1, &indirectBuf);
   2073 		m_ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf);
   2074 		m_ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand) + indirectOffset, buffer, GL_STATIC_DRAW);
   2075 		delete [] buffer;
   2076 
   2077 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "Setup draw indirect buffer");
   2078 
   2079 		m_ctx.drawElementsIndirect(primitiveToGL(primitive), indexTypeToGL(indexType), (const deInt8*)DE_NULL + indirectOffset);
   2080 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysIndirect()");
   2081 
   2082 		m_ctx.deleteBuffers(1, &indirectBuf);
   2083 	}
   2084 	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX)
   2085 	{
   2086 		m_ctx.drawElementsBaseVertex(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, baseVertex);
   2087 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsBaseVertex()");
   2088 	}
   2089 	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX)
   2090 	{
   2091 		m_ctx.drawElementsInstancedBaseVertex(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, instanceCount, baseVertex);
   2092 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsInstancedBaseVertex()");
   2093 	}
   2094 	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX)
   2095 	{
   2096 		m_ctx.drawRangeElementsBaseVertex(primitiveToGL(primitive), rangeStart, rangeEnd, vertexCount, indexTypeToGL(indexType), indexOffset, baseVertex);
   2097 		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawRangeElementsBaseVertex()");
   2098 	}
   2099 	else
   2100 		DE_ASSERT(DE_FALSE);
   2101 
   2102 	for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
   2103 	{
   2104 		if (m_arrays[arrayNdx]->isBound())
   2105 		{
   2106 			std::stringstream attribName;
   2107 			attribName << "a_" << arrayNdx;
   2108 
   2109 			deUint32 loc = m_ctx.getAttribLocation(m_programID, attribName.str().c_str());
   2110 
   2111 			m_ctx.disableVertexAttribArray(loc);
   2112 			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDisableVertexAttribArray()");
   2113 		}
   2114 	}
   2115 
   2116 	if (m_useVao)
   2117 		m_ctx.bindVertexArray(0);
   2118 
   2119 	m_ctx.useProgram(0);
   2120 	m_ctx.readPixels(m_screen, 0, 0, m_screen.getWidth(), m_screen.getHeight());
   2121 }
   2122 
   2123 // DrawTestSpec
   2124 
   2125 DrawTestSpec::AttributeSpec	DrawTestSpec::AttributeSpec::createAttributeArray (InputType inputType, OutputType outputType, Storage storage, Usage usage, int componentCount, int offset, int stride, bool normalize, int instanceDivisor)
   2126 {
   2127 	DrawTestSpec::AttributeSpec spec;
   2128 
   2129 	spec.inputType			= inputType;
   2130 	spec.outputType			= outputType;
   2131 	spec.storage			= storage;
   2132 	spec.usage				= usage;
   2133 	spec.componentCount		= componentCount;
   2134 	spec.offset				= offset;
   2135 	spec.stride				= stride;
   2136 	spec.normalize			= normalize;
   2137 	spec.instanceDivisor	= instanceDivisor;
   2138 
   2139 	spec.useDefaultAttribute= false;
   2140 
   2141 	return spec;
   2142 }
   2143 
   2144 DrawTestSpec::AttributeSpec	DrawTestSpec::AttributeSpec::createDefaultAttribute (InputType inputType, OutputType outputType, int componentCount)
   2145 {
   2146 	DE_ASSERT(inputType == INPUTTYPE_INT || inputType == INPUTTYPE_UNSIGNED_INT || inputType == INPUTTYPE_FLOAT);
   2147 	DE_ASSERT(inputType == INPUTTYPE_FLOAT || componentCount == 4);
   2148 
   2149 	DrawTestSpec::AttributeSpec spec;
   2150 
   2151 	spec.inputType				= inputType;
   2152 	spec.outputType				= outputType;
   2153 	spec.storage				= DrawTestSpec::STORAGE_LAST;
   2154 	spec.usage					= DrawTestSpec::USAGE_LAST;
   2155 	spec.componentCount			= componentCount;
   2156 	spec.offset					= 0;
   2157 	spec.stride					= 0;
   2158 	spec.normalize				= 0;
   2159 	spec.instanceDivisor		= 0;
   2160 
   2161 	spec.useDefaultAttribute	= true;
   2162 
   2163 	return spec;
   2164 }
   2165 
   2166 DrawTestSpec::AttributeSpec::AttributeSpec (void)
   2167 {
   2168 	inputType					= DrawTestSpec::INPUTTYPE_LAST;
   2169 	outputType					= DrawTestSpec::OUTPUTTYPE_LAST;
   2170 	storage						= DrawTestSpec::STORAGE_LAST;
   2171 	usage						= DrawTestSpec::USAGE_LAST;
   2172 	componentCount				= 0;
   2173 	offset						= 0;
   2174 	stride						= 0;
   2175 	normalize					= false;
   2176 	instanceDivisor				= 0;
   2177 	useDefaultAttribute			= false;
   2178 	additionalPositionAttribute = false;
   2179 	bgraComponentOrder			= false;
   2180 }
   2181 
   2182 int DrawTestSpec::AttributeSpec::hash (void) const
   2183 {
   2184 	if (useDefaultAttribute)
   2185 	{
   2186 		return 1 * int(inputType) + 7 * int(outputType) + 13 * componentCount;
   2187 	}
   2188 	else
   2189 	{
   2190 		return 1 * int(inputType) + 2 * int(outputType) + 3 * int(storage) + 5 * int(usage) + 7 * componentCount + 11 * offset + 13 * stride + 17 * (normalize ? 0 : 1) + 19 * instanceDivisor;
   2191 	}
   2192 }
   2193 
   2194 bool DrawTestSpec::AttributeSpec::valid (glu::ApiType ctxType) const
   2195 {
   2196 	const bool inputTypeFloat				= inputType == DrawTestSpec::INPUTTYPE_FLOAT || inputType  == DrawTestSpec::INPUTTYPE_FIXED || inputType == DrawTestSpec::INPUTTYPE_HALF;
   2197 	const bool inputTypeUnsignedInteger		= inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE || inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT || inputType  == DrawTestSpec::INPUTTYPE_UNSIGNED_INT || inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10;
   2198 	const bool inputTypeSignedInteger		= inputType == DrawTestSpec::INPUTTYPE_BYTE  || inputType == DrawTestSpec::INPUTTYPE_SHORT || inputType == DrawTestSpec::INPUTTYPE_INT || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
   2199 	const bool inputTypePacked				= inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
   2200 
   2201 	const bool outputTypeFloat				= outputType == DrawTestSpec::OUTPUTTYPE_FLOAT || outputType == DrawTestSpec::OUTPUTTYPE_VEC2  || outputType == DrawTestSpec::OUTPUTTYPE_VEC3  || outputType == DrawTestSpec::OUTPUTTYPE_VEC4;
   2202 	const bool outputTypeSignedInteger		= outputType == DrawTestSpec::OUTPUTTYPE_INT   || outputType == DrawTestSpec::OUTPUTTYPE_IVEC2 || outputType == DrawTestSpec::OUTPUTTYPE_IVEC3 || outputType == DrawTestSpec::OUTPUTTYPE_IVEC4;
   2203 	const bool outputTypeUnsignedInteger	= outputType == DrawTestSpec::OUTPUTTYPE_UINT  || outputType == DrawTestSpec::OUTPUTTYPE_UVEC2 || outputType == DrawTestSpec::OUTPUTTYPE_UVEC3 || outputType == DrawTestSpec::OUTPUTTYPE_UVEC4;
   2204 
   2205 	if (useDefaultAttribute)
   2206 	{
   2207 		if (inputType != DrawTestSpec::INPUTTYPE_INT && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT && inputType != DrawTestSpec::INPUTTYPE_FLOAT)
   2208 			return false;
   2209 
   2210 		if (inputType != DrawTestSpec::INPUTTYPE_FLOAT && componentCount != 4)
   2211 			return false;
   2212 
   2213 		// no casting allowed (undefined results)
   2214 		if (inputType == DrawTestSpec::INPUTTYPE_INT && !outputTypeSignedInteger)
   2215 			return false;
   2216 		if (inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT && !outputTypeUnsignedInteger)
   2217 			return false;
   2218 	}
   2219 
   2220 	if (inputTypePacked && componentCount != 4)
   2221 		return false;
   2222 
   2223 	// Invalid conversions:
   2224 
   2225 	// float -> [u]int
   2226 	if (inputTypeFloat && !outputTypeFloat)
   2227 		return false;
   2228 
   2229 	// uint -> int		(undefined results)
   2230 	if (inputTypeUnsignedInteger && outputTypeSignedInteger)
   2231 		return false;
   2232 
   2233 	// int -> uint		(undefined results)
   2234 	if (inputTypeSignedInteger && outputTypeUnsignedInteger)
   2235 		return false;
   2236 
   2237 	// packed -> non-float (packed formats are converted to floats)
   2238 	if (inputTypePacked && !outputTypeFloat)
   2239 		return false;
   2240 
   2241 	// Invalid normalize. Normalize is only valid if output type is float
   2242 	if (normalize && !outputTypeFloat)
   2243 		return false;
   2244 
   2245 	// Allow reverse order (GL_BGRA) only for packed and 4-component ubyte
   2246 	if (bgraComponentOrder && componentCount != 4)
   2247 		return false;
   2248 	if (bgraComponentOrder && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && inputType != DrawTestSpec::INPUTTYPE_INT_2_10_10_10 && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE)
   2249 		return false;
   2250 	if (bgraComponentOrder && normalize != true)
   2251 		return false;
   2252 
   2253 	// GLES2 limits
   2254 	if (ctxType == glu::ApiType::es(2,0))
   2255 	{
   2256 		if (inputType != DrawTestSpec::INPUTTYPE_FLOAT && inputType != DrawTestSpec::INPUTTYPE_FIXED &&
   2257 			inputType != DrawTestSpec::INPUTTYPE_BYTE  && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE &&
   2258 			inputType != DrawTestSpec::INPUTTYPE_SHORT && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT)
   2259 			return false;
   2260 
   2261 		if (!outputTypeFloat)
   2262 			return false;
   2263 
   2264 		if (bgraComponentOrder)
   2265 			return false;
   2266 	}
   2267 
   2268 	// GLES3 limits
   2269 	if (ctxType.getProfile() == glu::PROFILE_ES && ctxType.getMajorVersion() == 3)
   2270 	{
   2271 		if (bgraComponentOrder)
   2272 			return false;
   2273 	}
   2274 
   2275 	// No user pointers in GL core
   2276 	if (ctxType.getProfile() == glu::PROFILE_CORE)
   2277 	{
   2278 		if (!useDefaultAttribute && storage == DrawTestSpec::STORAGE_USER)
   2279 			return false;
   2280 	}
   2281 
   2282 	return true;
   2283 }
   2284 
   2285 bool DrawTestSpec::AttributeSpec::isBufferAligned (void) const
   2286 {
   2287 	const bool inputTypePacked = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
   2288 
   2289 	// Buffer alignment, offset is a multiple of underlying data type size?
   2290 	if (storage == STORAGE_BUFFER)
   2291 	{
   2292 		int dataTypeSize = gls::DrawTestSpec::inputTypeSize(inputType);
   2293 		if (inputTypePacked)
   2294 			dataTypeSize = 4;
   2295 
   2296 		if (offset % dataTypeSize != 0)
   2297 			return false;
   2298 	}
   2299 
   2300 	return true;
   2301 }
   2302 
   2303 bool DrawTestSpec::AttributeSpec::isBufferStrideAligned (void) const
   2304 {
   2305 	const bool inputTypePacked = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
   2306 
   2307 	// Buffer alignment, offset is a multiple of underlying data type size?
   2308 	if (storage == STORAGE_BUFFER)
   2309 	{
   2310 		int dataTypeSize = gls::DrawTestSpec::inputTypeSize(inputType);
   2311 		if (inputTypePacked)
   2312 			dataTypeSize = 4;
   2313 
   2314 		if (stride % dataTypeSize != 0)
   2315 			return false;
   2316 	}
   2317 
   2318 	return true;
   2319 }
   2320 
   2321 std::string DrawTestSpec::targetToString(Target target)
   2322 {
   2323 	DE_ASSERT(target < TARGET_LAST);
   2324 
   2325 	static const char* targets[] =
   2326 	{
   2327 		"element_array",	// TARGET_ELEMENT_ARRAY = 0,
   2328 		"array"				// TARGET_ARRAY,
   2329 	};
   2330 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(targets) == DrawTestSpec::TARGET_LAST);
   2331 
   2332 	return targets[(int)target];
   2333 }
   2334 
   2335 std::string DrawTestSpec::inputTypeToString(InputType type)
   2336 {
   2337 	DE_ASSERT(type < INPUTTYPE_LAST);
   2338 
   2339 	static const char* types[] =
   2340 	{
   2341 		"float",			// INPUTTYPE_FLOAT = 0,
   2342 		"fixed",			// INPUTTYPE_FIXED,
   2343 		"double",			// INPUTTYPE_DOUBLE
   2344 
   2345 		"byte",				// INPUTTYPE_BYTE,
   2346 		"short",			// INPUTTYPE_SHORT,
   2347 
   2348 		"unsigned_byte",	// INPUTTYPE_UNSIGNED_BYTE,
   2349 		"unsigned_short",	// INPUTTYPE_UNSIGNED_SHORT,
   2350 
   2351 		"int",						// INPUTTYPE_INT,
   2352 		"unsigned_int",				// INPUTTYPE_UNSIGNED_INT,
   2353 		"half",						// INPUTTYPE_HALF,
   2354 		"unsigned_int2_10_10_10",	// INPUTTYPE_UNSIGNED_INT_2_10_10_10,
   2355 		"int2_10_10_10"				// INPUTTYPE_INT_2_10_10_10,
   2356 	};
   2357 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(types) == DrawTestSpec::INPUTTYPE_LAST);
   2358 
   2359 	return types[(int)type];
   2360 }
   2361 
   2362 std::string DrawTestSpec::outputTypeToString(OutputType type)
   2363 {
   2364 	DE_ASSERT(type < OUTPUTTYPE_LAST);
   2365 
   2366 	static const char* types[] =
   2367 	{
   2368 		"float",		// OUTPUTTYPE_FLOAT = 0,
   2369 		"vec2",			// OUTPUTTYPE_VEC2,
   2370 		"vec3",			// OUTPUTTYPE_VEC3,
   2371 		"vec4",			// OUTPUTTYPE_VEC4,
   2372 
   2373 		"int",			// OUTPUTTYPE_INT,
   2374 		"uint",			// OUTPUTTYPE_UINT,
   2375 
   2376 		"ivec2",		// OUTPUTTYPE_IVEC2,
   2377 		"ivec3",		// OUTPUTTYPE_IVEC3,
   2378 		"ivec4",		// OUTPUTTYPE_IVEC4,
   2379 
   2380 		"uvec2",		// OUTPUTTYPE_UVEC2,
   2381 		"uvec3",		// OUTPUTTYPE_UVEC3,
   2382 		"uvec4",		// OUTPUTTYPE_UVEC4,
   2383 	};
   2384 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(types) == DrawTestSpec::OUTPUTTYPE_LAST);
   2385 
   2386 	return types[(int)type];
   2387 }
   2388 
   2389 std::string DrawTestSpec::usageTypeToString(Usage usage)
   2390 {
   2391 	DE_ASSERT(usage < USAGE_LAST);
   2392 
   2393 	static const char* usages[] =
   2394 	{
   2395 		"dynamic_draw",	// USAGE_DYNAMIC_DRAW = 0,
   2396 		"static_draw",	// USAGE_STATIC_DRAW,
   2397 		"stream_draw",	// USAGE_STREAM_DRAW,
   2398 
   2399 		"stream_read",	// USAGE_STREAM_READ,
   2400 		"stream_copy",	// USAGE_STREAM_COPY,
   2401 
   2402 		"static_read",	// USAGE_STATIC_READ,
   2403 		"static_copy",	// USAGE_STATIC_COPY,
   2404 
   2405 		"dynamic_read",	// USAGE_DYNAMIC_READ,
   2406 		"dynamic_copy",	// USAGE_DYNAMIC_COPY,
   2407 	};
   2408 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(usages) == DrawTestSpec::USAGE_LAST);
   2409 
   2410 	return usages[(int)usage];
   2411 }
   2412 
   2413 std::string	DrawTestSpec::storageToString (Storage storage)
   2414 {
   2415 	DE_ASSERT(storage < STORAGE_LAST);
   2416 
   2417 	static const char* storages[] =
   2418 	{
   2419 		"user_ptr",	// STORAGE_USER = 0,
   2420 		"buffer"	// STORAGE_BUFFER,
   2421 	};
   2422 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(storages) == DrawTestSpec::STORAGE_LAST);
   2423 
   2424 	return storages[(int)storage];
   2425 }
   2426 
   2427 std::string DrawTestSpec::primitiveToString (Primitive primitive)
   2428 {
   2429 	DE_ASSERT(primitive < PRIMITIVE_LAST);
   2430 
   2431 	static const char* primitives[] =
   2432 	{
   2433 		"points",					// PRIMITIVE_POINTS ,
   2434 		"triangles",				// PRIMITIVE_TRIANGLES,
   2435 		"triangle_fan",				// PRIMITIVE_TRIANGLE_FAN,
   2436 		"triangle_strip",			// PRIMITIVE_TRIANGLE_STRIP,
   2437 		"lines",					// PRIMITIVE_LINES
   2438 		"line_strip",				// PRIMITIVE_LINE_STRIP
   2439 		"line_loop",				// PRIMITIVE_LINE_LOOP
   2440 		"lines_adjacency",			// PRIMITIVE_LINES_ADJACENCY
   2441 		"line_strip_adjacency",		// PRIMITIVE_LINE_STRIP_ADJACENCY
   2442 		"triangles_adjacency",		// PRIMITIVE_TRIANGLES_ADJACENCY
   2443 		"triangle_strip_adjacency",	// PRIMITIVE_TRIANGLE_STRIP_ADJACENCY
   2444 	};
   2445 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(primitives) == DrawTestSpec::PRIMITIVE_LAST);
   2446 
   2447 	return primitives[(int)primitive];
   2448 }
   2449 
   2450 std::string DrawTestSpec::indexTypeToString (IndexType type)
   2451 {
   2452 	DE_ASSERT(type < DrawTestSpec::INDEXTYPE_LAST);
   2453 
   2454 	static const char* indexTypes[] =
   2455 	{
   2456 		"byte",		// INDEXTYPE_BYTE = 0,
   2457 		"short",	// INDEXTYPE_SHORT,
   2458 		"int",		// INDEXTYPE_INT,
   2459 	};
   2460 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(indexTypes) == DrawTestSpec::INDEXTYPE_LAST);
   2461 
   2462 	return indexTypes[(int)type];
   2463 }
   2464 
   2465 std::string DrawTestSpec::drawMethodToString (DrawTestSpec::DrawMethod method)
   2466 {
   2467 	DE_ASSERT(method < DrawTestSpec::DRAWMETHOD_LAST);
   2468 
   2469 	static const char* methods[] =
   2470 	{
   2471 		"draw_arrays",							//!< DRAWMETHOD_DRAWARRAYS
   2472 		"draw_arrays_instanced",				//!< DRAWMETHOD_DRAWARRAYS_INSTANCED
   2473 		"draw_arrays_indirect",					//!< DRAWMETHOD_DRAWARRAYS_INDIRECT
   2474 		"draw_elements",						//!< DRAWMETHOD_DRAWELEMENTS
   2475 		"draw_range_elements",					//!< DRAWMETHOD_DRAWELEMENTS_RANGED
   2476 		"draw_elements_instanced",				//!< DRAWMETHOD_DRAWELEMENTS_INSTANCED
   2477 		"draw_elements_indirect",				//!< DRAWMETHOD_DRAWELEMENTS_INDIRECT
   2478 		"draw_elements_base_vertex",			//!< DRAWMETHOD_DRAWELEMENTS_BASEVERTEX,
   2479 		"draw_elements_instanced_base_vertex",	//!< DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX,
   2480 		"draw_range_elements_base_vertex",		//!< DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX,
   2481 	};
   2482 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(methods) == DrawTestSpec::DRAWMETHOD_LAST);
   2483 
   2484 	return methods[(int)method];
   2485 }
   2486 
   2487 int DrawTestSpec::inputTypeSize (InputType type)
   2488 {
   2489 	DE_ASSERT(type < INPUTTYPE_LAST);
   2490 
   2491 	static const int size[] =
   2492 	{
   2493 		sizeof(float),		// INPUTTYPE_FLOAT = 0,
   2494 		sizeof(deInt32),	// INPUTTYPE_FIXED,
   2495 		sizeof(double),		// INPUTTYPE_DOUBLE
   2496 
   2497 		sizeof(deInt8),		// INPUTTYPE_BYTE,
   2498 		sizeof(deInt16),	// INPUTTYPE_SHORT,
   2499 
   2500 		sizeof(deUint8),	// INPUTTYPE_UNSIGNED_BYTE,
   2501 		sizeof(deUint16),	// INPUTTYPE_UNSIGNED_SHORT,
   2502 
   2503 		sizeof(deInt32),		// INPUTTYPE_INT,
   2504 		sizeof(deUint32),		// INPUTTYPE_UNSIGNED_INT,
   2505 		sizeof(deFloat16),		// INPUTTYPE_HALF,
   2506 		sizeof(deUint32) / 4,		// INPUTTYPE_UNSIGNED_INT_2_10_10_10,
   2507 		sizeof(deUint32) / 4		// INPUTTYPE_INT_2_10_10_10,
   2508 	};
   2509 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(size) == DrawTestSpec::INPUTTYPE_LAST);
   2510 
   2511 	return size[(int)type];
   2512 }
   2513 
   2514 int DrawTestSpec::indexTypeSize (IndexType type)
   2515 {
   2516 	DE_ASSERT(type < INDEXTYPE_LAST);
   2517 
   2518 	static const int size[] =
   2519 	{
   2520 		sizeof(deUint8),	// INDEXTYPE_BYTE,
   2521 		sizeof(deUint16),	// INDEXTYPE_SHORT,
   2522 		sizeof(deUint32),	// INDEXTYPE_INT,
   2523 	};
   2524 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(size) == DrawTestSpec::INDEXTYPE_LAST);
   2525 
   2526 	return size[(int)type];
   2527 }
   2528 
   2529 std::string DrawTestSpec::getName (void) const
   2530 {
   2531 	const MethodInfo	methodInfo	= getMethodInfo(drawMethod);
   2532 	const bool			hasFirst	= methodInfo.first;
   2533 	const bool			instanced	= methodInfo.instanced;
   2534 	const bool			ranged		= methodInfo.ranged;
   2535 	const bool			indexed		= methodInfo.indexed;
   2536 
   2537 	std::stringstream name;
   2538 
   2539 	for (size_t ndx = 0; ndx < attribs.size(); ++ndx)
   2540 	{
   2541 		const AttributeSpec& attrib = attribs[ndx];
   2542 
   2543 		if (attribs.size() > 1)
   2544 			name << "attrib" << ndx << "_";
   2545 
   2546 		if (ndx == 0|| attrib.additionalPositionAttribute)
   2547 			name << "pos_";
   2548 		else
   2549 			name << "col_";
   2550 
   2551 		if (attrib.useDefaultAttribute)
   2552 		{
   2553 			name
   2554 				<< "non_array_"
   2555 				<< DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "_"
   2556 				<< attrib.componentCount << "_"
   2557 				<< DrawTestSpec::outputTypeToString(attrib.outputType) << "_";
   2558 		}
   2559 		else
   2560 		{
   2561 			name
   2562 				<< DrawTestSpec::storageToString(attrib.storage) << "_"
   2563 				<< attrib.offset << "_"
   2564 				<< attrib.stride << "_"
   2565 				<< DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType);
   2566 			if (attrib.inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && attrib.inputType != DrawTestSpec::INPUTTYPE_INT_2_10_10_10)
   2567 				name << attrib.componentCount;
   2568 			name
   2569 				<< "_"
   2570 				<< (attrib.normalize ? "normalized_" : "")
   2571 				<< DrawTestSpec::outputTypeToString(attrib.outputType) << "_"
   2572 				<< DrawTestSpec::usageTypeToString(attrib.usage) << "_"
   2573 				<< attrib.instanceDivisor << "_";
   2574 		}
   2575 	}
   2576 
   2577 	if (indexed)
   2578 		name
   2579 			<< "index_" << DrawTestSpec::indexTypeToString(indexType) << "_"
   2580 			<< DrawTestSpec::storageToString(indexStorage) << "_"
   2581 			<< "offset" << indexPointerOffset << "_";
   2582 	if (hasFirst)
   2583 		name << "first" << first << "_";
   2584 	if (ranged)
   2585 		name << "ranged_" << indexMin << "_" << indexMax << "_";
   2586 	if (instanced)
   2587 		name << "instances" << instanceCount << "_";
   2588 
   2589 	switch (primitive)
   2590 	{
   2591 		case DrawTestSpec::PRIMITIVE_POINTS:
   2592 			name << "points_";
   2593 			break;
   2594 		case DrawTestSpec::PRIMITIVE_TRIANGLES:
   2595 			name << "triangles_";
   2596 			break;
   2597 		case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
   2598 			name << "triangle_fan_";
   2599 			break;
   2600 		case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
   2601 			name << "triangle_strip_";
   2602 			break;
   2603 		case DrawTestSpec::PRIMITIVE_LINES:
   2604 			name << "lines_";
   2605 			break;
   2606 		case DrawTestSpec::PRIMITIVE_LINE_STRIP:
   2607 			name << "line_strip_";
   2608 			break;
   2609 		case DrawTestSpec::PRIMITIVE_LINE_LOOP:
   2610 			name << "line_loop_";
   2611 			break;
   2612 		case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
   2613 			name << "line_adjancency";
   2614 			break;
   2615 		case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
   2616 			name << "line_strip_adjancency";
   2617 			break;
   2618 		case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
   2619 			name << "triangles_adjancency";
   2620 			break;
   2621 		case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
   2622 			name << "triangle_strip_adjancency";
   2623 			break;
   2624 		default:
   2625 			DE_ASSERT(false);
   2626 			break;
   2627 	}
   2628 
   2629 	name << primitiveCount;
   2630 
   2631 	return name.str();
   2632 }
   2633 
   2634 std::string DrawTestSpec::getDesc (void) const
   2635 {
   2636 	std::stringstream desc;
   2637 
   2638 	for (size_t ndx = 0; ndx < attribs.size(); ++ndx)
   2639 	{
   2640 		const AttributeSpec& attrib = attribs[ndx];
   2641 
   2642 		if (attrib.useDefaultAttribute)
   2643 		{
   2644 			desc
   2645 				<< "Attribute " << ndx << ": default, " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position ,") : ("color ,"))
   2646 				<< "input datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << ", "
   2647 				<< "input component count " << attrib.componentCount << ", "
   2648 				<< "used as " << DrawTestSpec::outputTypeToString(attrib.outputType) << ", ";
   2649 		}
   2650 		else
   2651 		{
   2652 			desc
   2653 				<< "Attribute " << ndx << ": " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position ,") : ("color ,"))
   2654 				<< "Storage in " << DrawTestSpec::storageToString(attrib.storage) << ", "
   2655 				<< "stride " << attrib.stride << ", "
   2656 				<< "input datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << ", "
   2657 				<< "input component count " << attrib.componentCount << ", "
   2658 				<< (attrib.normalize ? "normalized, " : "")
   2659 				<< "used as " << DrawTestSpec::outputTypeToString(attrib.outputType) << ", "
   2660 				<< "instance divisor " << attrib.instanceDivisor << ", ";
   2661 		}
   2662 	}
   2663 
   2664 	if (drawMethod == DRAWMETHOD_DRAWARRAYS)
   2665 	{
   2666 		desc
   2667 			<< "drawArrays(), "
   2668 			<< "first " << first << ", ";
   2669 	}
   2670 	else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INSTANCED)
   2671 	{
   2672 		desc
   2673 			<< "drawArraysInstanced(), "
   2674 			<< "first " << first << ", "
   2675 			<< "instance count " << instanceCount << ", ";
   2676 	}
   2677 	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS)
   2678 	{
   2679 		desc
   2680 			<< "drawElements(), "
   2681 			<< "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
   2682 			<< "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
   2683 			<< "index offset " << indexPointerOffset << ", ";
   2684 	}
   2685 	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED)
   2686 	{
   2687 		desc
   2688 			<< "drawElementsRanged(), "
   2689 			<< "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
   2690 			<< "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
   2691 			<< "index offset " << indexPointerOffset << ", "
   2692 			<< "range start " << indexMin << ", "
   2693 			<< "range end " << indexMax << ", ";
   2694 	}
   2695 	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED)
   2696 	{
   2697 		desc
   2698 			<< "drawElementsInstanced(), "
   2699 			<< "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
   2700 			<< "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
   2701 			<< "index offset " << indexPointerOffset << ", "
   2702 			<< "instance count " << instanceCount << ", ";
   2703 	}
   2704 	else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INDIRECT)
   2705 	{
   2706 		desc
   2707 			<< "drawArraysIndirect(), "
   2708 			<< "first " << first << ", "
   2709 			<< "instance count " << instanceCount << ", "
   2710 			<< "indirect offset " << indirectOffset << ", ";
   2711 	}
   2712 	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT)
   2713 	{
   2714 		desc
   2715 			<< "drawElementsIndirect(), "
   2716 			<< "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
   2717 			<< "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
   2718 			<< "index offset " << indexPointerOffset << ", "
   2719 			<< "instance count " << instanceCount << ", "
   2720 			<< "indirect offset " << indirectOffset << ", "
   2721 			<< "base vertex " << baseVertex << ", ";
   2722 	}
   2723 	else
   2724 		DE_ASSERT(DE_FALSE);
   2725 
   2726 	desc << primitiveCount;
   2727 
   2728 	switch (primitive)
   2729 	{
   2730 		case DrawTestSpec::PRIMITIVE_POINTS:
   2731 			desc << "points";
   2732 			break;
   2733 		case DrawTestSpec::PRIMITIVE_TRIANGLES:
   2734 			desc << "triangles";
   2735 			break;
   2736 		case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
   2737 			desc << "triangles (fan)";
   2738 			break;
   2739 		case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
   2740 			desc << "triangles (strip)";
   2741 			break;
   2742 		case DrawTestSpec::PRIMITIVE_LINES:
   2743 			desc << "lines";
   2744 			break;
   2745 		case DrawTestSpec::PRIMITIVE_LINE_STRIP:
   2746 			desc << "lines (strip)";
   2747 			break;
   2748 		case DrawTestSpec::PRIMITIVE_LINE_LOOP:
   2749 			desc << "lines (loop)";
   2750 			break;
   2751 		case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
   2752 			desc << "lines (adjancency)";
   2753 			break;
   2754 		case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
   2755 			desc << "lines (strip, adjancency)";
   2756 			break;
   2757 		case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
   2758 			desc << "triangles (adjancency)";
   2759 			break;
   2760 		case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
   2761 			desc << "triangles (strip, adjancency)";
   2762 			break;
   2763 		default:
   2764 			DE_ASSERT(false);
   2765 			break;
   2766 	}
   2767 
   2768 	return desc.str();
   2769 }
   2770 
   2771 std::string DrawTestSpec::getMultilineDesc (void) const
   2772 {
   2773 	std::stringstream desc;
   2774 
   2775 	for (size_t ndx = 0; ndx < attribs.size(); ++ndx)
   2776 	{
   2777 		const AttributeSpec& attrib = attribs[ndx];
   2778 
   2779 		if (attrib.useDefaultAttribute)
   2780 		{
   2781 			desc
   2782 				<< "Attribute " << ndx << ": default, " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position\n") : ("color\n"))
   2783 				<< "\tinput datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "\n"
   2784 				<< "\tinput component count " << attrib.componentCount << "\n"
   2785 				<< "\tused as " << DrawTestSpec::outputTypeToString(attrib.outputType) << "\n";
   2786 		}
   2787 		else
   2788 		{
   2789 			desc
   2790 				<< "Attribute " << ndx << ": " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position\n") : ("color\n"))
   2791 				<< "\tStorage in " << DrawTestSpec::storageToString(attrib.storage) << "\n"
   2792 				<< "\tstride " << attrib.stride << "\n"
   2793 				<< "\tinput datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "\n"
   2794 				<< "\tinput component count " << attrib.componentCount << "\n"
   2795 				<< (attrib.normalize ? "\tnormalized\n" : "")
   2796 				<< "\tused as " << DrawTestSpec::outputTypeToString(attrib.outputType) << "\n"
   2797 				<< "\tinstance divisor " << attrib.instanceDivisor << "\n";
   2798 		}
   2799 	}
   2800 
   2801 	if (drawMethod == DRAWMETHOD_DRAWARRAYS)
   2802 	{
   2803 		desc
   2804 			<< "drawArrays()\n"
   2805 			<< "\tfirst " << first << "\n";
   2806 	}
   2807 	else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INSTANCED)
   2808 	{
   2809 		desc
   2810 			<< "drawArraysInstanced()\n"
   2811 			<< "\tfirst " << first << "\n"
   2812 			<< "\tinstance count " << instanceCount << "\n";
   2813 	}
   2814 	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS)
   2815 	{
   2816 		desc
   2817 			<< "drawElements()\n"
   2818 			<< "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
   2819 			<< "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
   2820 			<< "\tindex offset " << indexPointerOffset << "\n";
   2821 	}
   2822 	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED)
   2823 	{
   2824 		desc
   2825 			<< "drawElementsRanged()\n"
   2826 			<< "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
   2827 			<< "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
   2828 			<< "\tindex offset " << indexPointerOffset << "\n"
   2829 			<< "\trange start " << indexMin << "\n"
   2830 			<< "\trange end " << indexMax << "\n";
   2831 	}
   2832 	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED)
   2833 	{
   2834 		desc
   2835 			<< "drawElementsInstanced()\n"
   2836 			<< "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
   2837 			<< "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
   2838 			<< "\tindex offset " << indexPointerOffset << "\n"
   2839 			<< "\tinstance count " << instanceCount << "\n";
   2840 	}
   2841 	else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INDIRECT)
   2842 	{
   2843 		desc
   2844 			<< "drawArraysIndirect()\n"
   2845 			<< "\tfirst " << first << "\n"
   2846 			<< "\tinstance count " << instanceCount << "\n"
   2847 			<< "\tindirect offset " << indirectOffset << "\n";
   2848 	}
   2849 	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT)
   2850 	{
   2851 		desc
   2852 			<< "drawElementsIndirect()\n"
   2853 			<< "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
   2854 			<< "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
   2855 			<< "\tindex offset " << indexPointerOffset << "\n"
   2856 			<< "\tinstance count " << instanceCount << "\n"
   2857 			<< "\tindirect offset " << indirectOffset << "\n"
   2858 			<< "\tbase vertex " << baseVertex << "\n";
   2859 	}
   2860 	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_BASEVERTEX)
   2861 	{
   2862 		desc
   2863 			<< "drawElementsBaseVertex()\n"
   2864 			<< "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
   2865 			<< "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
   2866 			<< "\tindex offset " << indexPointerOffset << "\n"
   2867 			<< "\tbase vertex " << baseVertex << "\n";
   2868 	}
   2869 	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX)
   2870 	{
   2871 		desc
   2872 			<< "drawElementsInstancedBaseVertex()\n"
   2873 			<< "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
   2874 			<< "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
   2875 			<< "\tindex offset " << indexPointerOffset << "\n"
   2876 			<< "\tinstance count " << instanceCount << "\n"
   2877 			<< "\tbase vertex " << baseVertex << "\n";
   2878 	}
   2879 	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX)
   2880 	{
   2881 		desc
   2882 			<< "drawRangeElementsBaseVertex()\n"
   2883 			<< "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
   2884 			<< "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
   2885 			<< "\tindex offset " << indexPointerOffset << "\n"
   2886 			<< "\tbase vertex " << baseVertex << "\n"
   2887 			<< "\trange start " << indexMin << "\n"
   2888 			<< "\trange end " << indexMax << "\n";
   2889 	}
   2890 	else
   2891 		DE_ASSERT(DE_FALSE);
   2892 
   2893 	desc << "\t" << primitiveCount << " ";
   2894 
   2895 	switch (primitive)
   2896 	{
   2897 		case DrawTestSpec::PRIMITIVE_POINTS:
   2898 			desc << "points";
   2899 			break;
   2900 		case DrawTestSpec::PRIMITIVE_TRIANGLES:
   2901 			desc << "triangles";
   2902 			break;
   2903 		case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
   2904 			desc << "triangles (fan)";
   2905 			break;
   2906 		case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
   2907 			desc << "triangles (strip)";
   2908 			break;
   2909 		case DrawTestSpec::PRIMITIVE_LINES:
   2910 			desc << "lines";
   2911 			break;
   2912 		case DrawTestSpec::PRIMITIVE_LINE_STRIP:
   2913 			desc << "lines (strip)";
   2914 			break;
   2915 		case DrawTestSpec::PRIMITIVE_LINE_LOOP:
   2916 			desc << "lines (loop)";
   2917 			break;
   2918 		case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
   2919 			desc << "lines (adjancency)";
   2920 			break;
   2921 		case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
   2922 			desc << "lines (strip, adjancency)";
   2923 			break;
   2924 		case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
   2925 			desc << "triangles (adjancency)";
   2926 			break;
   2927 		case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
   2928 			desc << "triangles (strip, adjancency)";
   2929 			break;
   2930 		default:
   2931 			DE_ASSERT(false);
   2932 			break;
   2933 	}
   2934 
   2935 	desc << "\n";
   2936 
   2937 	return desc.str();
   2938 }
   2939 
   2940 DrawTestSpec::DrawTestSpec (void)
   2941 {
   2942 	primitive			= PRIMITIVE_LAST;
   2943 	primitiveCount		= 0;
   2944 	drawMethod			= DRAWMETHOD_LAST;
   2945 	indexType			= INDEXTYPE_LAST;
   2946 	indexPointerOffset	= 0;
   2947 	indexStorage		= STORAGE_LAST;
   2948 	first				= 0;
   2949 	indexMin			= 0;
   2950 	indexMax			= 0;
   2951 	instanceCount		= 0;
   2952 	indirectOffset		= 0;
   2953 	baseVertex			= 0;
   2954 }
   2955 
   2956 int DrawTestSpec::hash (void) const
   2957 {
   2958 	// Use only drawmode-relevant values in "hashing" as the unrelevant values might not be set (causing non-deterministic behavior).
   2959 	const MethodInfo	methodInfo		= getMethodInfo(drawMethod);
   2960 	const bool			arrayed			= methodInfo.first;
   2961 	const bool			instanced		= methodInfo.instanced;
   2962 	const bool			ranged			= methodInfo.ranged;
   2963 	const bool			indexed			= methodInfo.indexed;
   2964 	const bool			indirect		= methodInfo.indirect;
   2965 	const bool			hasBaseVtx		= methodInfo.baseVertex;
   2966 
   2967 	const int			indexHash		= (!indexed)	? (0) : (int(indexType) + 10 * indexPointerOffset + 100 * int(indexStorage));
   2968 	const int			arrayHash		= (!arrayed)	? (0) : (first);
   2969 	const int			indexRangeHash	= (!ranged)		? (0) : (indexMin + 10 * indexMax);
   2970 	const int			instanceHash	= (!instanced)	? (0) : (instanceCount);
   2971 	const int			indirectHash	= (!indirect)	? (0) : (indirectOffset);
   2972 	const int			baseVtxHash		= (!hasBaseVtx)	? (0) : (baseVertex);
   2973 	const int			basicHash		= int(primitive) + 10 * primitiveCount + 100 * int(drawMethod);
   2974 
   2975 	return indexHash + 3 * arrayHash + 5 * indexRangeHash + 7 * instanceHash + 13 * basicHash + 17 * (int)attribs.size() + 19 * primitiveCount + 23 * indirectHash + 27 * baseVtxHash;
   2976 }
   2977 
   2978 bool DrawTestSpec::valid (void) const
   2979 {
   2980 	DE_ASSERT(apiType.getProfile() != glu::PROFILE_LAST);
   2981 	DE_ASSERT(primitive != PRIMITIVE_LAST);
   2982 	DE_ASSERT(drawMethod != DRAWMETHOD_LAST);
   2983 
   2984 	const MethodInfo methodInfo = getMethodInfo(drawMethod);
   2985 
   2986 	for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
   2987 		if (!attribs[ndx].valid(apiType))
   2988 			return false;
   2989 
   2990 	if (methodInfo.ranged)
   2991 	{
   2992 		deUint32 maxIndexValue = 0;
   2993 		if (indexType == INDEXTYPE_BYTE)
   2994 			maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_BYTE).ub.getValue();
   2995 		else if (indexType == INDEXTYPE_SHORT)
   2996 			maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_SHORT).us.getValue();
   2997 		else if (indexType == INDEXTYPE_INT)
   2998 			maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_INT).ui.getValue();
   2999 		else
   3000 			DE_ASSERT(DE_FALSE);
   3001 
   3002 		if (indexMin > indexMax)
   3003 			return false;
   3004 		if (indexMin < 0 || indexMax < 0)
   3005 			return false;
   3006 		if ((deUint32)indexMin > maxIndexValue || (deUint32)indexMax > maxIndexValue)
   3007 			return false;
   3008 	}
   3009 
   3010 	if (methodInfo.first && first < 0)
   3011 		return false;
   3012 
   3013 	// GLES2 limits
   3014 	if (apiType == glu::ApiType::es(2,0))
   3015 	{
   3016 		if (drawMethod != gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS && drawMethod != gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS)
   3017 			return false;
   3018 		if (drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS && (indexType != INDEXTYPE_BYTE && indexType != INDEXTYPE_SHORT))
   3019 			return false;
   3020 	}
   3021 
   3022 	// Indirect limitations
   3023 	if (methodInfo.indirect)
   3024 	{
   3025 		// Indirect offset alignment
   3026 		if (indirectOffset % 4 != 0)
   3027 			return false;
   3028 
   3029 		// All attribute arrays must be stored in a buffer
   3030 		for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
   3031 			if (!attribs[ndx].useDefaultAttribute && attribs[ndx].storage == gls::DrawTestSpec::STORAGE_USER)
   3032 				return false;
   3033 	}
   3034 	if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT)
   3035 	{
   3036 		// index offset must be convertable to firstIndex
   3037 		if (indexPointerOffset % gls::DrawTestSpec::indexTypeSize(indexType) != 0)
   3038 			return false;
   3039 
   3040 		// Indices must be in a buffer
   3041 		if (indexStorage != STORAGE_BUFFER)
   3042 			return false;
   3043 	}
   3044 
   3045 	// Do not allow user pointer in GL core
   3046 	if (apiType.getProfile() == glu::PROFILE_CORE)
   3047 	{
   3048 		if (methodInfo.indexed && indexStorage == DrawTestSpec::STORAGE_USER)
   3049 			return false;
   3050 	}
   3051 
   3052 	return true;
   3053 }
   3054 
   3055 DrawTestSpec::CompatibilityTestType DrawTestSpec::isCompatibilityTest (void) const
   3056 {
   3057 	const MethodInfo methodInfo = getMethodInfo(drawMethod);
   3058 
   3059 	bool bufferAlignmentBad = false;
   3060 	bool strideAlignmentBad = false;
   3061 
   3062 	// Attribute buffer alignment
   3063 	for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
   3064 		if (!attribs[ndx].isBufferAligned())
   3065 			bufferAlignmentBad = true;
   3066 
   3067 	// Attribute stride alignment
   3068 	for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
   3069 		if (!attribs[ndx].isBufferStrideAligned())
   3070 			strideAlignmentBad = true;
   3071 
   3072 	// Index buffer alignment
   3073 	if (methodInfo.indexed)
   3074 	{
   3075 		if (indexStorage == STORAGE_BUFFER)
   3076 		{
   3077 			int indexSize = 0;
   3078 			if (indexType == INDEXTYPE_BYTE)
   3079 				indexSize = 1;
   3080 			else if (indexType == INDEXTYPE_SHORT)
   3081 				indexSize = 2;
   3082 			else if (indexType == INDEXTYPE_INT)
   3083 				indexSize = 4;
   3084 			else
   3085 				DE_ASSERT(DE_FALSE);
   3086 
   3087 			if (indexPointerOffset % indexSize != 0)
   3088 				bufferAlignmentBad = true;
   3089 		}
   3090 	}
   3091 
   3092 	// \note combination bad alignment & stride is treated as bad offset
   3093 	if (bufferAlignmentBad)
   3094 		return COMPATIBILITY_UNALIGNED_OFFSET;
   3095 	else if (strideAlignmentBad)
   3096 		return COMPATIBILITY_UNALIGNED_STRIDE;
   3097 	else
   3098 		return COMPATIBILITY_NONE;
   3099 }
   3100 
   3101 // DrawTest
   3102 
   3103 DrawTest::DrawTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const DrawTestSpec& spec, const char* name, const char* desc)
   3104 	: TestCase			(testCtx, name, desc)
   3105 	, m_renderCtx		(renderCtx)
   3106 	, m_refBuffers		(DE_NULL)
   3107 	, m_refContext		(DE_NULL)
   3108 	, m_glesContext		(DE_NULL)
   3109 	, m_glArrayPack		(DE_NULL)
   3110 	, m_rrArrayPack		(DE_NULL)
   3111 	, m_maxDiffRed		(-1)
   3112 	, m_maxDiffGreen	(-1)
   3113 	, m_maxDiffBlue		(-1)
   3114 	, m_iteration		(0)
   3115 	, m_result			()	// \note no per-iteration result logging (only one iteration)
   3116 {
   3117 	addIteration(spec);
   3118 }
   3119 
   3120 DrawTest::DrawTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc)
   3121 	: TestCase			(testCtx, name, desc)
   3122 	, m_renderCtx		(renderCtx)
   3123 	, m_refBuffers		(DE_NULL)
   3124 	, m_refContext		(DE_NULL)
   3125 	, m_glesContext		(DE_NULL)
   3126 	, m_glArrayPack		(DE_NULL)
   3127 	, m_rrArrayPack		(DE_NULL)
   3128 	, m_maxDiffRed		(-1)
   3129 	, m_maxDiffGreen	(-1)
   3130 	, m_maxDiffBlue		(-1)
   3131 	, m_iteration		(0)
   3132 	, m_result			(testCtx.getLog(), "Iteration result: ")
   3133 {
   3134 }
   3135 
   3136 DrawTest::~DrawTest	(void)
   3137 {
   3138 	deinit();
   3139 }
   3140 
   3141 void DrawTest::addIteration (const DrawTestSpec& spec, const char* description)
   3142 {
   3143 	// Validate spec
   3144 	const bool validSpec = spec.valid();
   3145 	DE_ASSERT(validSpec);
   3146 
   3147 	if (!validSpec)
   3148 		return;
   3149 
   3150 	// Check the context type is the same with other iterations
   3151 	if (!m_specs.empty())
   3152 	{
   3153 		const bool validContext = m_specs[0].apiType == spec.apiType;
   3154 		DE_ASSERT(validContext);
   3155 
   3156 		if (!validContext)
   3157 			return;
   3158 	}
   3159 
   3160 	m_specs.push_back(spec);
   3161 
   3162 	if (description)
   3163 		m_iteration_descriptions.push_back(std::string(description));
   3164 	else
   3165 		m_iteration_descriptions.push_back(std::string());
   3166 }
   3167 
   3168 void DrawTest::init (void)
   3169 {
   3170 	const int						renderTargetWidth	= de::min(MAX_RENDER_TARGET_SIZE, m_renderCtx.getRenderTarget().getWidth());
   3171 	const int						renderTargetHeight	= de::min(MAX_RENDER_TARGET_SIZE, m_renderCtx.getRenderTarget().getHeight());
   3172 	sglr::ReferenceContextLimits	limits				(m_renderCtx);
   3173 	bool							useVao				= false;
   3174 
   3175 	m_glesContext = new sglr::GLContext(m_renderCtx, m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight));
   3176 
   3177 	if (m_renderCtx.getType().getAPI() == glu::ApiType::es(2,0) || m_renderCtx.getType().getAPI() == glu::ApiType::es(3,0))
   3178 		useVao = false;
   3179 	else if (contextSupports(m_renderCtx.getType(), glu::ApiType::es(3,1)) || glu::isContextTypeGLCore(m_renderCtx.getType()))
   3180 		useVao = true;
   3181 	else
   3182 		DE_ASSERT(!"Unknown context type");
   3183 
   3184 	DE_ASSERT(!m_specs.empty());
   3185 	DE_ASSERT(contextSupports(m_renderCtx.getType(), m_specs[0].apiType));
   3186 
   3187 	m_refBuffers	= new sglr::ReferenceContextBuffers(m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, renderTargetWidth, renderTargetHeight);
   3188 	m_refContext	= new sglr::ReferenceContext(limits, m_refBuffers->getColorbuffer(), m_refBuffers->getDepthbuffer(), m_refBuffers->getStencilbuffer());
   3189 
   3190 	m_glArrayPack	= new AttributePack(m_testCtx, m_renderCtx, *m_glesContext, tcu::UVec2(renderTargetWidth, renderTargetHeight), useVao, true);
   3191 	m_rrArrayPack	= new AttributePack(m_testCtx, m_renderCtx, *m_refContext,  tcu::UVec2(renderTargetWidth, renderTargetHeight), useVao, false);
   3192 
   3193 	m_maxDiffRed	= deCeilFloatToInt32(256.0f * (6.0f / (1 << m_renderCtx.getRenderTarget().getPixelFormat().redBits)));
   3194 	m_maxDiffGreen	= deCeilFloatToInt32(256.0f * (6.0f / (1 << m_renderCtx.getRenderTarget().getPixelFormat().greenBits)));
   3195 	m_maxDiffBlue	= deCeilFloatToInt32(256.0f * (6.0f / (1 << m_renderCtx.getRenderTarget().getPixelFormat().blueBits)));
   3196 }
   3197 
   3198 void DrawTest::deinit (void)
   3199 {
   3200 	delete m_glArrayPack;
   3201 	delete m_rrArrayPack;
   3202 	delete m_refBuffers;
   3203 	delete m_refContext;
   3204 	delete m_glesContext;
   3205 
   3206 	m_glArrayPack	= DE_NULL;
   3207 	m_rrArrayPack	= DE_NULL;
   3208 	m_refBuffers	= DE_NULL;
   3209 	m_refContext	= DE_NULL;
   3210 	m_glesContext	= DE_NULL;
   3211 }
   3212 
   3213 DrawTest::IterateResult DrawTest::iterate (void)
   3214 {
   3215 	const int					specNdx			= (m_iteration / 2);
   3216 	const bool					drawStep		= (m_iteration % 2) == 0;
   3217 	const bool					compareStep		= (m_iteration % 2) == 1;
   3218 	const IterateResult			iterateResult	= ((size_t)m_iteration + 1 == m_specs.size()*2) ? (STOP) : (CONTINUE);
   3219 	const DrawTestSpec&			spec			= m_specs[specNdx];
   3220 	const bool					updateProgram	= (m_iteration == 0) || (drawStep && !checkSpecsShaderCompatible(m_specs[specNdx], m_specs[specNdx-1])); // try to use the same shader in all iterations
   3221 	IterationLogSectionEmitter	sectionEmitter	(m_testCtx.getLog(), specNdx, m_specs.size(), m_iteration_descriptions[specNdx], drawStep && m_specs.size()!=1);
   3222 
   3223 	if (drawStep)
   3224 	{
   3225 		const MethodInfo	methodInfo				= getMethodInfo(spec.drawMethod);
   3226 		const bool			indexed					= methodInfo.indexed;
   3227 		const bool			instanced				= methodInfo.instanced;
   3228 		const bool			ranged					= methodInfo.ranged;
   3229 		const bool			hasFirst				= methodInfo.first;
   3230 		const bool			hasBaseVtx				= methodInfo.baseVertex;
   3231 
   3232 		const size_t		primitiveElementCount	= getElementCount(spec.primitive, spec.primitiveCount);						// !< elements to be drawn
   3233 		const int			indexMin				= (ranged) ? (spec.indexMin) : (0);
   3234 		const int			firstAddition			= (hasFirst) ? (spec.first) : (0);
   3235 		const int			baseVertexAddition		= (hasBaseVtx && spec.baseVertex > 0) ? ( spec.baseVertex) : (0);			// spec.baseVertex > 0 => Create bigger attribute buffer
   3236 		const int			indexBase				= (hasBaseVtx && spec.baseVertex < 0) ? (-spec.baseVertex) : (0);			// spec.baseVertex < 0 => Create bigger indices
   3237 		const size_t		elementCount			= primitiveElementCount + indexMin + firstAddition + baseVertexAddition;	// !< elements in buffer (buffer should have at least primitiveElementCount ACCESSIBLE (index range, first) elements)
   3238 		const int			maxElementIndex			= (int)primitiveElementCount + indexMin + firstAddition - 1;
   3239 		const int			indexMax				= de::max(0, (ranged) ? (de::clamp<int>(spec.indexMax, 0, maxElementIndex)) : (maxElementIndex));
   3240 		float				coordScale				= getCoordScale(spec);
   3241 		float				colorScale				= getColorScale(spec);
   3242 
   3243 		rr::GenericVec4		nullAttribValue;
   3244 
   3245 		// Log info
   3246 		m_testCtx.getLog() << TestLog::Message << spec.getMultilineDesc() << TestLog::EndMessage;
   3247 		m_testCtx.getLog() << TestLog::Message << TestLog::EndMessage; // extra line for clarity
   3248 
   3249 		// Data
   3250 
   3251 		m_glArrayPack->clearArrays();
   3252 		m_rrArrayPack->clearArrays();
   3253 
   3254 		for (int attribNdx = 0; attribNdx < (int)spec.attribs.size(); attribNdx++)
   3255 		{
   3256 			DrawTestSpec::AttributeSpec attribSpec		= spec.attribs[attribNdx];
   3257 			const bool					isPositionAttr	= (attribNdx == 0) || (attribSpec.additionalPositionAttribute);
   3258 
   3259 			if (attribSpec.useDefaultAttribute)
   3260 			{
   3261 				const int		seed		= 10 * attribSpec.hash() + 100 * spec.hash() + attribNdx;
   3262 				rr::GenericVec4 attribValue = RandomArrayGenerator::generateAttributeValue(seed, attribSpec.inputType);
   3263 
   3264 				m_glArrayPack->newArray(DrawTestSpec::STORAGE_USER);
   3265 				m_rrArrayPack->newArray(DrawTestSpec::STORAGE_USER);
   3266 
   3267 				m_glArrayPack->getArray(attribNdx)->setupArray(false, 0, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, false, 0, 0, attribValue, isPositionAttr, false);
   3268 				m_rrArrayPack->getArray(attribNdx)->setupArray(false, 0, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, false, 0, 0, attribValue, isPositionAttr, false);
   3269 			}
   3270 			else
   3271 			{
   3272 				const int					seed					= attribSpec.hash() + 100 * spec.hash() + attribNdx;
   3273 				const size_t				elementSize				= attribSpec.componentCount * DrawTestSpec::inputTypeSize(attribSpec.inputType);
   3274 				const size_t				stride					= (attribSpec.stride == 0) ? (elementSize) : (attribSpec.stride);
   3275 				const size_t				evaluatedElementCount	= (instanced && attribSpec.instanceDivisor > 0) ? (spec.instanceCount / attribSpec.instanceDivisor + 1) : (elementCount);
   3276 				const size_t				referencedElementCount	= (ranged) ? (de::max<size_t>(evaluatedElementCount, spec.indexMax + 1)) : (evaluatedElementCount);
   3277 				const size_t				bufferSize				= attribSpec.offset + stride * (referencedElementCount - 1) + elementSize;
   3278 				const char*					data					= RandomArrayGenerator::generateArray(seed, (int)referencedElementCount, attribSpec.componentCount, attribSpec.offset, (int)stride, attribSpec.inputType);
   3279 
   3280 				try
   3281 				{
   3282 					m_glArrayPack->newArray(attribSpec.storage);
   3283 					m_rrArrayPack->newArray(attribSpec.storage);
   3284 
   3285 					m_glArrayPack->getArray(attribNdx)->data(DrawTestSpec::TARGET_ARRAY, bufferSize, data, attribSpec.usage);
   3286 					m_rrArrayPack->getArray(attribNdx)->data(DrawTestSpec::TARGET_ARRAY, bufferSize, data, attribSpec.usage);
   3287 
   3288 					m_glArrayPack->getArray(attribNdx)->setupArray(true, attribSpec.offset, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, attribSpec.normalize, attribSpec.stride, attribSpec.instanceDivisor, nullAttribValue, isPositionAttr, attribSpec.bgraComponentOrder);
   3289 					m_rrArrayPack->getArray(attribNdx)->setupArray(true, attribSpec.offset, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, attribSpec.normalize, attribSpec.stride, attribSpec.instanceDivisor, nullAttribValue, isPositionAttr, attribSpec.bgraComponentOrder);
   3290 
   3291 					delete [] data;
   3292 					data = NULL;
   3293 				}
   3294 				catch (...)
   3295 				{
   3296 					delete [] data;
   3297 					throw;
   3298 				}
   3299 			}
   3300 		}
   3301 
   3302 		// Shader program
   3303 		if (updateProgram)
   3304 		{
   3305 			m_glArrayPack->updateProgram();
   3306 			m_rrArrayPack->updateProgram();
   3307 		}
   3308 
   3309 		// Draw
   3310 		try
   3311 		{
   3312 			// indices
   3313 			if (indexed)
   3314 			{
   3315 				const int		seed				= spec.hash();
   3316 				const size_t	indexElementSize	= DrawTestSpec::indexTypeSize(spec.indexType);
   3317 				const size_t	indexArraySize		= spec.indexPointerOffset + indexElementSize * elementCount;
   3318 				const char*		indexArray			= RandomArrayGenerator::generateIndices(seed, (int)elementCount, spec.indexType, spec.indexPointerOffset, indexMin, indexMax, indexBase);
   3319 				const char*		indexPointerBase	= (spec.indexStorage == DrawTestSpec::STORAGE_USER) ? (indexArray) : ((char*)DE_NULL);
   3320 				const char*		indexPointer		= indexPointerBase + spec.indexPointerOffset;
   3321 
   3322 				de::UniquePtr<AttributeArray> glArray	(new AttributeArray(spec.indexStorage, *m_glesContext));
   3323 				de::UniquePtr<AttributeArray> rrArray	(new AttributeArray(spec.indexStorage, *m_refContext));
   3324 
   3325 				try
   3326 				{
   3327 					glArray->data(DrawTestSpec::TARGET_ELEMENT_ARRAY, indexArraySize, indexArray, DrawTestSpec::USAGE_STATIC_DRAW);
   3328 					rrArray->data(DrawTestSpec::TARGET_ELEMENT_ARRAY, indexArraySize, indexArray, DrawTestSpec::USAGE_STATIC_DRAW);
   3329 
   3330 					m_glArrayPack->render(spec.primitive, spec.drawMethod, 0, (int)primitiveElementCount, spec.indexType, indexPointer, spec.indexMin, spec.indexMax, spec.instanceCount, spec.indirectOffset, spec.baseVertex, coordScale, colorScale, glArray.get());
   3331 					m_rrArrayPack->render(spec.primitive, spec.drawMethod, 0, (int)primitiveElementCount, spec.indexType, indexPointer, spec.indexMin, spec.indexMax, spec.instanceCount, spec.indirectOffset, spec.baseVertex, coordScale, colorScale, rrArray.get());
   3332 
   3333 					delete [] indexArray;
   3334 					indexArray = NULL;
   3335 				}
   3336 				catch (...)
   3337 				{
   3338 					delete [] indexArray;
   3339 					throw;
   3340 				}
   3341 			}
   3342 			else
   3343 			{
   3344 				m_glArrayPack->render(spec.primitive, spec.drawMethod, spec.first, (int)primitiveElementCount, DrawTestSpec::INDEXTYPE_LAST, DE_NULL, 0, 0, spec.instanceCount, spec.indirectOffset, 0, coordScale, colorScale, DE_NULL);
   3345 				m_rrArrayPack->render(spec.primitive, spec.drawMethod, spec.first, (int)primitiveElementCount, DrawTestSpec::INDEXTYPE_LAST, DE_NULL, 0, 0, spec.instanceCount, spec.indirectOffset, 0, coordScale, colorScale, DE_NULL);
   3346 			}
   3347 		}
   3348 		catch (glu::Error& err)
   3349 		{
   3350 			// GL Errors are ok if the mode is not properly aligned
   3351 
   3352 			const DrawTestSpec::CompatibilityTestType ctype = spec.isCompatibilityTest();
   3353 
   3354 			m_testCtx.getLog() << TestLog::Message << "Got error: " << err.what() << TestLog::EndMessage;
   3355 
   3356 			if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET)
   3357 				m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
   3358 			else if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
   3359 				m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
   3360 			else
   3361 				throw;
   3362 		}
   3363 	}
   3364 	else if (compareStep)
   3365 	{
   3366 		if (!compare(spec.primitive))
   3367 		{
   3368 			const DrawTestSpec::CompatibilityTestType ctype = spec.isCompatibilityTest();
   3369 
   3370 			if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET)
   3371 				m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
   3372 			else if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
   3373 				m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
   3374 			else
   3375 				m_result.addResult(QP_TEST_RESULT_FAIL, "Image comparison failed.");
   3376 		}
   3377 	}
   3378 	else
   3379 	{
   3380 		DE_ASSERT(false);
   3381 		return STOP;
   3382 	}
   3383 
   3384 	m_result.setTestContextResult(m_testCtx);
   3385 
   3386 	m_iteration++;
   3387 	return iterateResult;
   3388 }
   3389 
   3390 enum PrimitiveClass
   3391 {
   3392 	PRIMITIVECLASS_POINT = 0,
   3393 	PRIMITIVECLASS_LINE,
   3394 	PRIMITIVECLASS_TRIANGLE,
   3395 
   3396 	PRIMITIVECLASS_LAST
   3397 };
   3398 
   3399 static PrimitiveClass getDrawPrimitiveClass (gls::DrawTestSpec::Primitive primitiveType)
   3400 {
   3401 	switch (primitiveType)
   3402 	{
   3403 		case gls::DrawTestSpec::PRIMITIVE_POINTS:
   3404 			return PRIMITIVECLASS_POINT;
   3405 
   3406 		case gls::DrawTestSpec::PRIMITIVE_LINES:
   3407 		case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP:
   3408 		case gls::DrawTestSpec::PRIMITIVE_LINE_LOOP:
   3409 		case gls::DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
   3410 		case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
   3411 			return PRIMITIVECLASS_LINE;
   3412 
   3413 		case gls::DrawTestSpec::PRIMITIVE_TRIANGLES:
   3414 		case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
   3415 		case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
   3416 		case gls::DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
   3417 		case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
   3418 			return PRIMITIVECLASS_TRIANGLE;
   3419 
   3420 		default:
   3421 			DE_ASSERT(false);
   3422 			return PRIMITIVECLASS_LAST;
   3423 	}
   3424 }
   3425 
   3426 static bool isBlack (const tcu::RGBA& c)
   3427 {
   3428 	// ignore alpha channel
   3429 	return c.getRed() == 0 && c.getGreen() == 0 && c.getBlue() == 0;
   3430 }
   3431 
   3432 static bool isEdgeTripletComponent (int c1, int c2, int c3, int renderTargetDifference)
   3433 {
   3434 	const int	roundingDifference	= 2 * renderTargetDifference; // src and dst pixels rounded to different directions
   3435 	const int	d1					= c2 - c1;
   3436 	const int	d2					= c3 - c2;
   3437 	const int	rampDiff			= de::abs(d2 - d1);
   3438 
   3439 	return rampDiff > roundingDifference;
   3440 }
   3441 
   3442 static bool isEdgeTriplet (const tcu::RGBA& c1, const tcu::RGBA& c2, const tcu::RGBA& c3, const tcu::IVec3& renderTargetThreshold)
   3443 {
   3444 	// black (background color) and non-black is always an edge
   3445 	{
   3446 		const bool b1 = isBlack(c1);
   3447 		const bool b2 = isBlack(c2);
   3448 		const bool b3 = isBlack(c3);
   3449 
   3450 		// both pixels with coverage and pixels without coverage
   3451 		if ((b1 && b2 && b3) == false && (b1 || b2 || b3) == true)
   3452 			return true;
   3453 		// all black
   3454 		if (b1 && b2 && b3)
   3455 			return false;
   3456 		// all with coverage
   3457 		DE_ASSERT(!b1 && !b2 && !b3);
   3458 	}
   3459 
   3460 	// Color is always linearly interpolated => component values change nearly linearly
   3461 	// in any constant direction on triangle hull. (df/dx ~= C).
   3462 
   3463 	// Edge detection (this function) is run against the reference image
   3464 	// => no dithering to worry about
   3465 
   3466 	return	isEdgeTripletComponent(c1.getRed(),		c2.getRed(),	c3.getRed(),	renderTargetThreshold.x())	||
   3467 			isEdgeTripletComponent(c1.getGreen(),	c2.getGreen(),	c3.getGreen(),	renderTargetThreshold.y())	||
   3468 			isEdgeTripletComponent(c1.getBlue(),	c2.getBlue(),	c3.getBlue(),	renderTargetThreshold.z());
   3469 }
   3470 
   3471 static bool pixelNearEdge (int x, int y, const tcu::Surface& ref, const tcu::IVec3& renderTargetThreshold)
   3472 {
   3473 	// should not be called for edge pixels
   3474 	DE_ASSERT(x >= 1 && x <= ref.getWidth()-2);
   3475 	DE_ASSERT(y >= 1 && y <= ref.getHeight()-2);
   3476 
   3477 	// horizontal
   3478 
   3479 	for (int dy = -1; dy < 2; ++dy)
   3480 	{
   3481 		const tcu::RGBA c1 = ref.getPixel(x-1, y+dy);
   3482 		const tcu::RGBA c2 = ref.getPixel(x,   y+dy);
   3483 		const tcu::RGBA c3 = ref.getPixel(x+1, y+dy);
   3484 		if (isEdgeTriplet(c1, c2, c3, renderTargetThreshold))
   3485 			return true;
   3486 	}
   3487 
   3488 	// vertical
   3489 
   3490 	for (int dx = -1; dx < 2; ++dx)
   3491 	{
   3492 		const tcu::RGBA c1 = ref.getPixel(x+dx, y-1);
   3493 		const tcu::RGBA c2 = ref.getPixel(x+dx, y);
   3494 		const tcu::RGBA c3 = ref.getPixel(x+dx, y+1);
   3495 		if (isEdgeTriplet(c1, c2, c3, renderTargetThreshold))
   3496 			return true;
   3497 	}
   3498 
   3499 	return false;
   3500 }
   3501 
   3502 static deUint32 getVisualizationGrayscaleColor (const tcu::RGBA& c)
   3503 {
   3504 	// make triangle coverage and error pixels obvious by converting coverage to grayscale
   3505 	if (isBlack(c))
   3506 		return 0;
   3507 	else
   3508 		return 50u + (deUint32)(c.getRed() + c.getBlue() + c.getGreen()) / 8u;
   3509 }
   3510 
   3511 static bool pixelNearLineIntersection (int x, int y, const tcu::Surface& target)
   3512 {
   3513 	// should not be called for edge pixels
   3514 	DE_ASSERT(x >= 1 && x <= target.getWidth()-2);
   3515 	DE_ASSERT(y >= 1 && y <= target.getHeight()-2);
   3516 
   3517 	int coveredPixels = 0;
   3518 
   3519 	for (int dy = -1; dy < 2; dy++)
   3520 	for (int dx = -1; dx < 2; dx++)
   3521 	{
   3522 		const bool targetCoverage = !isBlack(target.getPixel(x+dx, y+dy));
   3523 		if (targetCoverage)
   3524 		{
   3525 			++coveredPixels;
   3526 
   3527 			// A single thin line cannot have more than 3 covered pixels in a 3x3 area
   3528 			if (coveredPixels >= 4)
   3529 				return true;
   3530 		}
   3531 	}
   3532 
   3533 	return false;
   3534 }
   3535 
   3536 // search 3x3 are for matching color
   3537 static bool pixelNeighborhoodContainsColor (const tcu::Surface& target, int x, int y, const tcu::RGBA& color, const tcu::IVec3& compareThreshold)
   3538 {
   3539 	// should not be called for edge pixels
   3540 	DE_ASSERT(x >= 1 && x <= target.getWidth()-2);
   3541 	DE_ASSERT(y >= 1 && y <= target.getHeight()-2);
   3542 
   3543 	for (int dy = -1; dy < 2; dy++)
   3544 	for (int dx = -1; dx < 2; dx++)
   3545 	{
   3546 		const tcu::RGBA	targetCmpPixel	= target.getPixel(x+dx, y+dy);
   3547 		const int		r				= deAbs32(color.getRed()	- targetCmpPixel.getRed());
   3548 		const int		g				= deAbs32(color.getGreen()	- targetCmpPixel.getGreen());
   3549 		const int		b				= deAbs32(color.getBlue()	- targetCmpPixel.getBlue());
   3550 
   3551 		if (r <= compareThreshold.x() && g <= compareThreshold.y() && b <= compareThreshold.z())
   3552 			return true;
   3553 	}
   3554 
   3555 	return false;
   3556 }
   3557 
   3558 // search 3x3 are for matching coverage (coverage == (color != background color))
   3559 static bool pixelNeighborhoodContainsCoverage (const tcu::Surface& target, int x, int y, bool coverage)
   3560 {
   3561 	// should not be called for edge pixels
   3562 	DE_ASSERT(x >= 1 && x <= target.getWidth()-2);
   3563 	DE_ASSERT(y >= 1 && y <= target.getHeight()-2);
   3564 
   3565 	for (int dy = -1; dy < 2; dy++)
   3566 	for (int dx = -1; dx < 2; dx++)
   3567 	{
   3568 		const bool targetCmpCoverage = !isBlack(target.getPixel(x+dx, y+dy));
   3569 		if (targetCmpCoverage == coverage)
   3570 			return true;
   3571 	}
   3572 
   3573 	return false;
   3574 }
   3575 
   3576 static bool edgeRelaxedImageCompare (tcu::TestLog& log, const char* imageSetName, const char* imageSetDesc, const tcu::Surface& reference, const tcu::Surface& result, const tcu::IVec3& compareThreshold, const tcu::IVec3& renderTargetThreshold, int maxAllowedInvalidPixels)
   3577 {
   3578 	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
   3579 
   3580 	const tcu::IVec4	green						(0, 255, 0, 255);
   3581 	const tcu::IVec4	errorColor					(255, 0, 0, 255);
   3582 	const int			width						= reference.getWidth();
   3583 	const int			height						= reference.getHeight();
   3584 	tcu::TextureLevel	errorMask					(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), width, height);
   3585 	int					numFailingPixels			= 0;
   3586 
   3587 	// clear errormask edges which would otherwise be transparent
   3588 
   3589 	tcu::clear(tcu::getSubregion(errorMask.getAccess(), 0,			0,			width,	1),			green);
   3590 	tcu::clear(tcu::getSubregion(errorMask.getAccess(), 0,			height-1,	width,	1),			green);
   3591 	tcu::clear(tcu::getSubregion(errorMask.getAccess(), 0,			0,			1,		height),	green);
   3592 	tcu::clear(tcu::getSubregion(errorMask.getAccess(), width-1,	0,			1,		height),	green);
   3593 
   3594 	// skip edge pixels since coverage on edge cannot be verified
   3595 
   3596 	for (int y = 1; y < height - 1; ++y)
   3597 	for (int x = 1; x < width - 1; ++x)
   3598 	{
   3599 		const tcu::RGBA	refPixel			= reference.getPixel(x, y);
   3600 		const tcu::RGBA	screenPixel			= result.getPixel(x, y);
   3601 		const bool		isOkReferencePixel	= pixelNeighborhoodContainsColor(result, x, y, refPixel, compareThreshold);			// screen image has a matching pixel nearby (~= If something is drawn on reference, it must be drawn to screen too.)
   3602 		const bool		isOkScreenPixel		= pixelNeighborhoodContainsColor(reference, x, y, screenPixel, compareThreshold);	// reference image has a matching pixel nearby (~= If something is drawn on screen, it must be drawn to reference too.)
   3603 
   3604 		if (isOkScreenPixel && isOkReferencePixel)
   3605 		{
   3606 			// pixel valid, write greenish pixels to make the result image easier to read
   3607 			const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
   3608 			errorMask.getAccess().setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
   3609 		}
   3610 		else if (!pixelNearEdge(x, y, reference, renderTargetThreshold))
   3611 		{
   3612 			// non-edge pixel values must be within threshold of the reference values
   3613 			errorMask.getAccess().setPixel(errorColor, x, y);
   3614 			++numFailingPixels;
   3615 		}
   3616 		else
   3617 		{
   3618 			// we are on/near an edge, verify only coverage (coverage == not background colored)
   3619 			const bool	referenceCoverage		= !isBlack(refPixel);
   3620 			const bool	screenCoverage			= !isBlack(screenPixel);
   3621 			const bool	isOkReferenceCoverage	= pixelNeighborhoodContainsCoverage(result, x, y, referenceCoverage);	// Check reference pixel against screen pixel
   3622 			const bool	isOkScreenCoverage		= pixelNeighborhoodContainsCoverage(reference, x, y, screenCoverage);	// Check screen pixels against reference pixel
   3623 
   3624 			if (isOkScreenCoverage && isOkReferenceCoverage)
   3625 			{
   3626 				// pixel valid, write greenish pixels to make the result image easier to read
   3627 				const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
   3628 				errorMask.getAccess().setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
   3629 			}
   3630 			else
   3631 			{
   3632 				// coverage does not match
   3633 				errorMask.getAccess().setPixel(errorColor, x, y);
   3634 				++numFailingPixels;
   3635 			}
   3636 		}
   3637 	}
   3638 
   3639 	log	<< TestLog::Message
   3640 		<< "Comparing images:\n"
   3641 		<< "\tallowed deviation in pixel positions = 1\n"
   3642 		<< "\tnumber of allowed invalid pixels = " << maxAllowedInvalidPixels << "\n"
   3643 		<< "\tnumber of invalid pixels = " << numFailingPixels
   3644 		<< TestLog::EndMessage;
   3645 
   3646 	if (numFailingPixels > maxAllowedInvalidPixels)
   3647 	{
   3648 		log << TestLog::Message
   3649 			<< "Image comparison failed. Color threshold = (" << compareThreshold.x() << ", " << compareThreshold.y() << ", " << compareThreshold.z() << ")"
   3650 			<< TestLog::EndMessage
   3651 			<< TestLog::ImageSet(imageSetName, imageSetDesc)
   3652 			<< TestLog::Image("Result",		"Result",		result)
   3653 			<< TestLog::Image("Reference",	"Reference",	reference)
   3654 			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
   3655 			<< TestLog::EndImageSet;
   3656 
   3657 		return false;
   3658 	}
   3659 	else
   3660 	{
   3661 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
   3662 			<< TestLog::Image("Result", "Result", result)
   3663 			<< TestLog::EndImageSet;
   3664 
   3665 		return true;
   3666 	}
   3667 }
   3668 
   3669 static bool intersectionRelaxedLineImageCompare (tcu::TestLog& log, const char* imageSetName, const char* imageSetDesc, const tcu::Surface& reference, const tcu::Surface& result, const tcu::IVec3& compareThreshold, int maxAllowedInvalidPixels)
   3670 {
   3671 	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
   3672 
   3673 	const tcu::IVec4	green						(0, 255, 0, 255);
   3674 	const tcu::IVec4	errorColor					(255, 0, 0, 255);
   3675 	const int			width						= reference.getWidth();
   3676 	const int			height						= reference.getHeight();
   3677 	tcu::TextureLevel	errorMask					(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), width, height);
   3678 	int					numFailingPixels			= 0;
   3679 
   3680 	// clear errormask edges which would otherwise be transparent
   3681 
   3682 	tcu::clear(tcu::getSubregion(errorMask.getAccess(), 0,			0,			width,	1),			green);
   3683 	tcu::clear(tcu::getSubregion(errorMask.getAccess(), 0,			height-1,	width,	1),			green);
   3684 	tcu::clear(tcu::getSubregion(errorMask.getAccess(), 0,			0,			1,		height),	green);
   3685 	tcu::clear(tcu::getSubregion(errorMask.getAccess(), width-1,	0,			1,		height),	green);
   3686 
   3687 	// skip edge pixels since coverage on edge cannot be verified
   3688 
   3689 	for (int y = 1; y < height - 1; ++y)
   3690 	for (int x = 1; x < width - 1; ++x)
   3691 	{
   3692 		const tcu::RGBA	refPixel			= reference.getPixel(x, y);
   3693 		const tcu::RGBA	screenPixel			= result.getPixel(x, y);
   3694 		const bool		isOkScreenPixel		= pixelNeighborhoodContainsColor(reference, x, y, screenPixel, compareThreshold);	// reference image has a matching pixel nearby (~= If something is drawn on screen, it must be drawn to reference too.)
   3695 		const bool		isOkReferencePixel	= pixelNeighborhoodContainsColor(result, x, y, refPixel, compareThreshold);			// screen image has a matching pixel nearby (~= If something is drawn on reference, it must be drawn to screen too.)
   3696 
   3697 		if (isOkScreenPixel && isOkReferencePixel)
   3698 		{
   3699 			// pixel valid, write greenish pixels to make the result image easier to read
   3700 			const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
   3701 			errorMask.getAccess().setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
   3702 		}
   3703 		else if (!pixelNearLineIntersection(x, y, reference) &&
   3704 				 !pixelNearLineIntersection(x, y, result))
   3705 		{
   3706 			// non-intersection pixel values must be within threshold of the reference values
   3707 			errorMask.getAccess().setPixel(errorColor, x, y);
   3708 			++numFailingPixels;
   3709 		}
   3710 		else
   3711 		{
   3712 			// pixel is near a line intersection
   3713 			// we are on/near an edge, verify only coverage (coverage == not background colored)
   3714 			const bool	referenceCoverage		= !isBlack(refPixel);
   3715 			const bool	screenCoverage			= !isBlack(screenPixel);
   3716 			const bool	isOkScreenCoverage		= pixelNeighborhoodContainsCoverage(reference, x, y, screenCoverage);	// Check screen pixels against reference pixel
   3717 			const bool	isOkReferenceCoverage	= pixelNeighborhoodContainsCoverage(result, x, y, referenceCoverage);	// Check reference pixel against screen pixel
   3718 
   3719 			if (isOkScreenCoverage && isOkReferenceCoverage)
   3720 			{
   3721 				// pixel valid, write greenish pixels to make the result image easier to read
   3722 				const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
   3723 				errorMask.getAccess().setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
   3724 			}
   3725 			else
   3726 			{
   3727 				// coverage does not match
   3728 				errorMask.getAccess().setPixel(errorColor, x, y);
   3729 				++numFailingPixels;
   3730 			}
   3731 		}
   3732 	}
   3733 
   3734 	log	<< TestLog::Message
   3735 		<< "Comparing images:\n"
   3736 		<< "\tallowed deviation in pixel positions = 1\n"
   3737 		<< "\tnumber of allowed invalid pixels = " << maxAllowedInvalidPixels << "\n"
   3738 		<< "\tnumber of invalid pixels = " << numFailingPixels
   3739 		<< TestLog::EndMessage;
   3740 
   3741 	if (numFailingPixels > maxAllowedInvalidPixels)
   3742 	{
   3743 		log << TestLog::Message
   3744 			<< "Image comparison failed. Color threshold = (" << compareThreshold.x() << ", " << compareThreshold.y() << ", " << compareThreshold.z() << ")"
   3745 			<< TestLog::EndMessage
   3746 			<< TestLog::ImageSet(imageSetName, imageSetDesc)
   3747 			<< TestLog::Image("Result",		"Result",		result)
   3748 			<< TestLog::Image("Reference",	"Reference",	reference)
   3749 			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
   3750 			<< TestLog::EndImageSet;
   3751 
   3752 		return false;
   3753 	}
   3754 	else
   3755 	{
   3756 		log << TestLog::ImageSet(imageSetName, imageSetDesc)
   3757 			<< TestLog::Image("Result", "Result", result)
   3758 			<< TestLog::EndImageSet;
   3759 
   3760 		return true;
   3761 	}
   3762 }
   3763 
   3764 bool DrawTest::compare (gls::DrawTestSpec::Primitive primitiveType)
   3765 {
   3766 	const tcu::Surface&	ref		= m_rrArrayPack->getSurface();
   3767 	const tcu::Surface&	screen	= m_glArrayPack->getSurface();
   3768 
   3769 	if (m_renderCtx.getRenderTarget().getNumSamples() > 1)
   3770 	{
   3771 		// \todo [mika] Improve compare when using multisampling
   3772 		m_testCtx.getLog() << tcu::TestLog::Message << "Warning: Comparision of result from multisample render targets are not as stricts as without multisampling. Might produce false positives!" << tcu::TestLog::EndMessage;
   3773 		return tcu::fuzzyCompare(m_testCtx.getLog(), "Compare Results", "Compare Results", ref.getAccess(), screen.getAccess(), 0.3f, tcu::COMPARE_LOG_RESULT);
   3774 	}
   3775 	else
   3776 	{
   3777 		const PrimitiveClass primitiveClass = getDrawPrimitiveClass(primitiveType);
   3778 
   3779 		switch (primitiveClass)
   3780 		{
   3781 			case PRIMITIVECLASS_POINT:
   3782 			{
   3783 				// Point are extremely unlikely to have overlapping regions, don't allow any no extra / missing pixels
   3784 				const int maxAllowedInvalidPixelsWithPoints = 0;
   3785 				return tcu::intThresholdPositionDeviationErrorThresholdCompare(m_testCtx.getLog(),
   3786 																			   "CompareResult",
   3787 																			   "Result of rendering",
   3788 																			   ref.getAccess(),
   3789 																			   screen.getAccess(),
   3790 																			   tcu::UVec4(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue, 256),
   3791 																			   tcu::IVec3(1, 1, 0),					//!< 3x3 search kernel
   3792 																			   true,								//!< relax comparison on the image boundary
   3793 																			   maxAllowedInvalidPixelsWithPoints,	//!< error threshold
   3794 																			   tcu::COMPARE_LOG_RESULT);
   3795 			}
   3796 
   3797 			case PRIMITIVECLASS_LINE:
   3798 			{
   3799 				// Lines can potentially have a large number of overlapping pixels. Pixel comparison may potentially produce
   3800 				// false negatives in such pixels if for example the pixel in question is overdrawn by another line in the
   3801 				// reference image but not in the resultin image. Relax comparison near line intersection points (areas) and
   3802 				// compare only coverage, not color, in such pixels
   3803 				const int maxAllowedInvalidPixelsWithLines = 5; // line are allowed to have a few bad pixels
   3804 				return intersectionRelaxedLineImageCompare(m_testCtx.getLog(),
   3805 														   "CompareResult",
   3806 														   "Result of rendering",
   3807 														   ref,
   3808 														   screen,
   3809 														   tcu::IVec3(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue),
   3810 														   maxAllowedInvalidPixelsWithLines);
   3811 			}
   3812 
   3813 			case PRIMITIVECLASS_TRIANGLE:
   3814 			{
   3815 				// Triangles are likely to partially or fully overlap. Pixel difference comparison is fragile in pixels
   3816 				// where there could be potential overlapping since the  pixels might be covered by one triangle in the
   3817 				// reference image and by the other in the result image. Relax comparsion near primitive edges and
   3818 				// compare only coverage, not color, in such pixels.
   3819 				const int			maxAllowedInvalidPixelsWithTriangles	= 10;
   3820 				const tcu::IVec3	renderTargetThreshold					= m_renderCtx.getRenderTarget().getPixelFormat().getColorThreshold().toIVec().xyz();
   3821 
   3822 				return edgeRelaxedImageCompare(m_testCtx.getLog(),
   3823 											   "CompareResult",
   3824 											   "Result of rendering",
   3825 											   ref,
   3826 											   screen,
   3827 											   tcu::IVec3(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue),
   3828 											   renderTargetThreshold,
   3829 											   maxAllowedInvalidPixelsWithTriangles);
   3830 			}
   3831 
   3832 			default:
   3833 				DE_ASSERT(false);
   3834 				return false;
   3835 		}
   3836 	}
   3837 }
   3838 
   3839 float DrawTest::getCoordScale (const DrawTestSpec& spec) const
   3840 {
   3841 	float maxValue = 1.0f;
   3842 
   3843 	for (int arrayNdx = 0; arrayNdx < (int)spec.attribs.size(); arrayNdx++)
   3844 	{
   3845 		DrawTestSpec::AttributeSpec attribSpec		= spec.attribs[arrayNdx];
   3846 		const bool					isPositionAttr	= (arrayNdx == 0) || (attribSpec.additionalPositionAttribute);
   3847 		float						attrMaxValue	= 0;
   3848 
   3849 		if (!isPositionAttr)
   3850 			continue;
   3851 
   3852 		if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
   3853 		{
   3854 			if (attribSpec.normalize)
   3855 				attrMaxValue += 1.0f;
   3856 			else
   3857 				attrMaxValue += 1024.0;
   3858 		}
   3859 		else if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10)
   3860 		{
   3861 			if (attribSpec.normalize)
   3862 				attrMaxValue += 1.0f;
   3863 			else
   3864 				attrMaxValue += 512.0;
   3865 		}
   3866 		else
   3867 		{
   3868 			const float max = GLValue::getMaxValue(attribSpec.inputType).toFloat();
   3869 
   3870 			attrMaxValue += (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType)) ? (1.0f) : (max * 1.1f);
   3871 		}
   3872 
   3873 		if (attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC4
   3874 			|| attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC4
   3875 			|| attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC4)
   3876 				attrMaxValue *= 2;
   3877 
   3878 		maxValue += attrMaxValue;
   3879 	}
   3880 
   3881 	return 1.0f / maxValue;
   3882 }
   3883 
   3884 float DrawTest::getColorScale (const DrawTestSpec& spec) const
   3885 {
   3886 	float colorScale = 1.0f;
   3887 
   3888 	for (int arrayNdx = 1; arrayNdx < (int)spec.attribs.size(); arrayNdx++)
   3889 	{
   3890 		DrawTestSpec::AttributeSpec attribSpec		= spec.attribs[arrayNdx];
   3891 		const bool					isPositionAttr	= (arrayNdx == 0) || (attribSpec.additionalPositionAttribute);
   3892 
   3893 		if (isPositionAttr)
   3894 			continue;
   3895 
   3896 		if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
   3897 		{
   3898 			if (!attribSpec.normalize)
   3899 				colorScale *= 1.0 / 1024.0;
   3900 		}
   3901 		else if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10)
   3902 		{
   3903 			if (!attribSpec.normalize)
   3904 				colorScale *= 1.0 / 512.0;
   3905 		}
   3906 		else
   3907 		{
   3908 			const float max = GLValue::getMaxValue(attribSpec.inputType).toFloat();
   3909 
   3910 			colorScale *= (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType) ? 1.0f : float(1.0 / double(max)));
   3911 			if (attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC4 ||
   3912 				attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC4 ||
   3913 				attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC4)
   3914 				colorScale *= (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType) ? 1.0f : float(1.0 / double(max)));
   3915 		}
   3916 	}
   3917 
   3918 	return colorScale;
   3919 }
   3920 
   3921 } // gls
   3922 } // deqp
   3923