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