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