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