glsDrawTest.cpp revision d6148171f88da1301f053e2e0236afc69416137c
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(m_value + other.getValue()); }
401		inline WrappedType<Type>	operator*		(const WrappedType<Type>& other) const	{ return WrappedType<Type>::create(m_value * other.getValue()); }
402		inline WrappedType<Type>	operator/		(const WrappedType<Type>& other) const	{ return WrappedType<Type>::create(m_value / other.getValue()); }
403		inline WrappedType<Type>	operator-		(const WrappedType<Type>& other) const	{ return WrappedType<Type>::create(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 : 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 : 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 : 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 : 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// AttriuteArray
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						subdata				(DrawTestSpec::Target target, int offset, int size, const char* data);
898	void						setupArray			(bool bound, int offset, int size, DrawTestSpec::InputType inType, DrawTestSpec::OutputType outType, bool normalized, int stride, int instanceDivisor, const rr::GenericVec4& defaultAttrib, bool isPositionAttr, bool bgraComponentOrder);
899	void						bindAttribute		(deUint32 loc);
900	void						bindIndexArray		(DrawTestSpec::Target storage);
901
902	int							getComponentCount	(void) const { return m_componentCount; }
903	DrawTestSpec::Target		getTarget			(void) const { return m_target; }
904	DrawTestSpec::InputType		getInputType		(void) const { return m_inputType; }
905	DrawTestSpec::OutputType	getOutputType		(void) const { return m_outputType; }
906	DrawTestSpec::Storage		getStorageType		(void) const { return m_storage; }
907	bool						getNormalized		(void) const { return m_normalize; }
908	int							getStride			(void) const { return m_stride; }
909	bool						isBound				(void) const { return m_bound; }
910	bool						isPositionAttribute	(void) const { return m_isPositionAttr; }
911
912private:
913	DrawTestSpec::Storage		m_storage;
914	sglr::Context&				m_ctx;
915	deUint32					m_glBuffer;
916
917	int							m_size;
918	char*						m_data;
919	int							m_componentCount;
920	bool						m_bound;
921	DrawTestSpec::Target		m_target;
922	DrawTestSpec::InputType		m_inputType;
923	DrawTestSpec::OutputType	m_outputType;
924	bool						m_normalize;
925	int							m_stride;
926	int							m_offset;
927	rr::GenericVec4				m_defaultAttrib;
928	int							m_instanceDivisor;
929	bool						m_isPositionAttr;
930	bool						m_bgraOrder;
931};
932
933AttributeArray::AttributeArray (DrawTestSpec::Storage storage, sglr::Context& context)
934	: m_storage			(storage)
935	, m_ctx				(context)
936	, m_glBuffer		(0)
937	, m_size			(0)
938	, m_data			(DE_NULL)
939	, m_componentCount	(1)
940	, m_bound			(false)
941	, m_target			(DrawTestSpec::TARGET_ARRAY)
942	, m_inputType		(DrawTestSpec::INPUTTYPE_FLOAT)
943	, m_outputType		(DrawTestSpec::OUTPUTTYPE_VEC4)
944	, m_normalize		(false)
945	, m_stride			(0)
946	, m_offset			(0)
947	, m_instanceDivisor	(0)
948	, m_isPositionAttr	(false)
949	, m_bgraOrder		(false)
950{
951	if (m_storage == DrawTestSpec::STORAGE_BUFFER)
952	{
953		m_ctx.genBuffers(1, &m_glBuffer);
954		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glGenBuffers()");
955	}
956}
957
958AttributeArray::~AttributeArray	(void)
959{
960	if (m_storage == DrawTestSpec::STORAGE_BUFFER)
961	{
962		m_ctx.deleteBuffers(1, &m_glBuffer);
963		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDeleteBuffers()");
964	}
965	else if (m_storage == DrawTestSpec::STORAGE_USER)
966		delete[] m_data;
967	else
968		DE_ASSERT(false);
969}
970
971void AttributeArray::data (DrawTestSpec::Target target, size_t size, const char* ptr, DrawTestSpec::Usage usage)
972{
973	m_size = (int)size;
974	m_target = target;
975
976	if (m_storage == DrawTestSpec::STORAGE_BUFFER)
977	{
978		m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
979		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
980
981		m_ctx.bufferData(targetToGL(target), size, ptr, usageToGL(usage));
982		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferData()");
983	}
984	else if (m_storage == DrawTestSpec::STORAGE_USER)
985	{
986		if (m_data)
987			delete[] m_data;
988
989		m_data = new char[size];
990		std::memcpy(m_data, ptr, size);
991	}
992	else
993		DE_ASSERT(false);
994}
995
996void AttributeArray::subdata (DrawTestSpec::Target target, int offset, int size, const char* ptr)
997{
998	m_target = target;
999
1000	if (m_storage == DrawTestSpec::STORAGE_BUFFER)
1001	{
1002		m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
1003		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
1004
1005		m_ctx.bufferSubData(targetToGL(target), offset, size, ptr);
1006		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBufferSubData()");
1007	}
1008	else if (m_storage == DrawTestSpec::STORAGE_USER)
1009		std::memcpy(m_data + offset, ptr, size);
1010	else
1011		DE_ASSERT(false);
1012}
1013
1014void 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)
1015{
1016	m_componentCount	= size;
1017	m_bound				= bound;
1018	m_inputType			= inputType;
1019	m_outputType		= outType;
1020	m_normalize			= normalized;
1021	m_stride			= stride;
1022	m_offset			= offset;
1023	m_defaultAttrib		= defaultAttrib;
1024	m_instanceDivisor	= instanceDivisor;
1025	m_isPositionAttr	= isPositionAttr;
1026	m_bgraOrder			= bgraComponentOrder;
1027}
1028
1029void AttributeArray::bindAttribute (deUint32 loc)
1030{
1031	if (!isBound())
1032	{
1033		switch (m_inputType)
1034		{
1035			case DrawTestSpec::INPUTTYPE_FLOAT:
1036			{
1037				tcu::Vec4 attr = m_defaultAttrib.get<float>();
1038
1039				switch (m_componentCount)
1040				{
1041					case 1: m_ctx.vertexAttrib1f(loc, attr.x()); break;
1042					case 2: m_ctx.vertexAttrib2f(loc, attr.x(), attr.y()); break;
1043					case 3: m_ctx.vertexAttrib3f(loc, attr.x(), attr.y(), attr.z()); break;
1044					case 4: m_ctx.vertexAttrib4f(loc, attr.x(), attr.y(), attr.z(), attr.w()); break;
1045					default: DE_ASSERT(DE_FALSE); break;
1046				}
1047				break;
1048			}
1049			case DrawTestSpec::INPUTTYPE_INT:
1050			{
1051				tcu::IVec4 attr = m_defaultAttrib.get<deInt32>();
1052				m_ctx.vertexAttribI4i(loc, attr.x(), attr.y(), attr.z(), attr.w());
1053				break;
1054			}
1055			case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:
1056			{
1057				tcu::UVec4 attr = m_defaultAttrib.get<deUint32>();
1058				m_ctx.vertexAttribI4ui(loc, attr.x(), attr.y(), attr.z(), attr.w());
1059				break;
1060			}
1061			default:
1062				DE_ASSERT(DE_FALSE);
1063				break;
1064		}
1065	}
1066	else
1067	{
1068		const deUint8* basePtr = DE_NULL;
1069
1070		if (m_storage == DrawTestSpec::STORAGE_BUFFER)
1071		{
1072			m_ctx.bindBuffer(targetToGL(m_target), m_glBuffer);
1073			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
1074
1075			basePtr = DE_NULL;
1076		}
1077		else if (m_storage == DrawTestSpec::STORAGE_USER)
1078		{
1079			m_ctx.bindBuffer(targetToGL(m_target), 0);
1080			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glBindBuffer()");
1081
1082			basePtr = (const deUint8*)m_data;
1083		}
1084		else
1085			DE_ASSERT(DE_FALSE);
1086
1087		if (!inputTypeIsFloatType(m_inputType))
1088		{
1089			// Input is not float type
1090
1091			if (outputTypeIsFloatType(m_outputType))
1092			{
1093				const int size = (m_bgraOrder) ? (GL_BGRA) : (m_componentCount);
1094
1095				DE_ASSERT(!(m_bgraOrder && m_componentCount != 4));
1096
1097				// Output type is float type
1098				m_ctx.vertexAttribPointer(loc, size, inputTypeToGL(m_inputType), m_normalize, m_stride, basePtr + m_offset);
1099				GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
1100			}
1101			else
1102			{
1103				// Output type is int type
1104				m_ctx.vertexAttribIPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_stride, basePtr + m_offset);
1105				GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribIPointer()");
1106			}
1107		}
1108		else
1109		{
1110			// Input type is float type
1111
1112			// Output type must be float type
1113			DE_ASSERT(outputTypeIsFloatType(m_outputType));
1114
1115			m_ctx.vertexAttribPointer(loc, m_componentCount, inputTypeToGL(m_inputType), m_normalize, m_stride, basePtr + m_offset);
1116			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glVertexAttribPointer()");
1117		}
1118
1119		if (m_instanceDivisor)
1120			m_ctx.vertexAttribDivisor(loc, m_instanceDivisor);
1121	}
1122}
1123
1124void AttributeArray::bindIndexArray (DrawTestSpec::Target target)
1125{
1126	if (m_storage == DrawTestSpec::STORAGE_USER)
1127	{
1128	}
1129	else if (m_storage == DrawTestSpec::STORAGE_BUFFER)
1130	{
1131		m_ctx.bindBuffer(targetToGL(target), m_glBuffer);
1132	}
1133}
1134
1135// DrawTestShaderProgram
1136
1137class DrawTestShaderProgram : public sglr::ShaderProgram
1138{
1139public:
1140												DrawTestShaderProgram		(const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays);
1141
1142	void										shadeVertices				(const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const;
1143	void										shadeFragments				(rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const;
1144
1145private:
1146	static std::string							genVertexSource				(const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays);
1147	static std::string							genFragmentSource			(const glu::RenderContext& ctx);
1148	static void									generateShaderParams		(std::map<std::string, std::string>& params, glu::ContextType type);
1149	static rr::GenericVecType					mapOutputType				(const DrawTestSpec::OutputType& type);
1150	static int									getComponentCount			(const DrawTestSpec::OutputType& type);
1151
1152	static sglr::pdec::ShaderProgramDeclaration createProgramDeclaration	(const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays);
1153
1154	std::vector<int>							m_componentCount;
1155	std::vector<bool>							m_isCoord;
1156	std::vector<rr::GenericVecType>				m_attrType;
1157};
1158
1159DrawTestShaderProgram::DrawTestShaderProgram (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays)
1160	: sglr::ShaderProgram	(createProgramDeclaration(ctx, arrays))
1161	, m_componentCount		(arrays.size())
1162	, m_isCoord				(arrays.size())
1163	, m_attrType			(arrays.size())
1164{
1165	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1166	{
1167		m_componentCount[arrayNdx]	= getComponentCount(arrays[arrayNdx]->getOutputType());
1168		m_isCoord[arrayNdx]			= arrays[arrayNdx]->isPositionAttribute();
1169		m_attrType[arrayNdx]		= mapOutputType(arrays[arrayNdx]->getOutputType());
1170	}
1171}
1172
1173template <typename T>
1174void calcShaderColorCoord (tcu::Vec2& coord, tcu::Vec3& color, const tcu::Vector<T, 4>& attribValue, bool isCoordinate, int numComponents)
1175{
1176	if (isCoordinate)
1177		switch (numComponents)
1178		{
1179			case 1:	coord += tcu::Vec2((float)attribValue.x(),						(float)attribValue.x());					break;
1180			case 2:	coord += tcu::Vec2((float)attribValue.x(),						(float)attribValue.y());					break;
1181			case 3:	coord += tcu::Vec2((float)attribValue.x() + attribValue.z(),	(float)attribValue.y());					break;
1182			case 4:	coord += tcu::Vec2((float)attribValue.x() + attribValue.z(),	(float)attribValue.y() + attribValue.w());	break;
1183
1184			default:
1185				DE_ASSERT(false);
1186		}
1187	else
1188	{
1189		switch (numComponents)
1190		{
1191			case 1:
1192				color = color * (float)attribValue.x();
1193				break;
1194
1195			case 2:
1196				color.x() = color.x() * attribValue.x();
1197				color.y() = color.y() * attribValue.y();
1198				break;
1199
1200			case 3:
1201				color.x() = color.x() * attribValue.x();
1202				color.y() = color.y() * attribValue.y();
1203				color.z() = color.z() * attribValue.z();
1204				break;
1205
1206			case 4:
1207				color.x() = color.x() * attribValue.x() * attribValue.w();
1208				color.y() = color.y() * attribValue.y() * attribValue.w();
1209				color.z() = color.z() * attribValue.z() * attribValue.w();
1210				break;
1211
1212			default:
1213				DE_ASSERT(false);
1214		}
1215	}
1216}
1217
1218void DrawTestShaderProgram::shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
1219{
1220	const float	u_coordScale = getUniformByName("u_coordScale").value.f;
1221	const float u_colorScale = getUniformByName("u_colorScale").value.f;
1222
1223	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1224	{
1225		const size_t varyingLocColor = 0;
1226
1227		rr::VertexPacket& packet = *packets[packetNdx];
1228
1229		// Calc output color
1230		tcu::Vec2 coord = tcu::Vec2(0.0, 0.0);
1231		tcu::Vec3 color = tcu::Vec3(1.0, 1.0, 1.0);
1232
1233		for (int attribNdx = 0; attribNdx < (int)m_attrType.size(); attribNdx++)
1234		{
1235			const int	numComponents	= m_componentCount[attribNdx];
1236			const bool	isCoord			= m_isCoord[attribNdx];
1237
1238			switch (m_attrType[attribNdx])
1239			{
1240				case rr::GENERICVECTYPE_FLOAT:	calcShaderColorCoord(coord, color, rr::readVertexAttribFloat(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents);	break;
1241				case rr::GENERICVECTYPE_INT32:	calcShaderColorCoord(coord, color, rr::readVertexAttribInt	(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents);	break;
1242				case rr::GENERICVECTYPE_UINT32:	calcShaderColorCoord(coord, color, rr::readVertexAttribUint	(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx), isCoord, numComponents);	break;
1243				default:
1244					DE_ASSERT(false);
1245			}
1246		}
1247
1248		// Transform position
1249		{
1250			packet.position = tcu::Vec4(u_coordScale * coord.x(), u_coordScale * coord.y(), 1.0f, 1.0f);
1251			packet.pointSize = 1.0f;
1252		}
1253
1254		// Pass color to FS
1255		{
1256			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);
1257		}
1258	}
1259}
1260
1261void DrawTestShaderProgram::shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
1262{
1263	const size_t varyingLocColor = 0;
1264
1265	for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1266	{
1267		rr::FragmentPacket& packet = packets[packetNdx];
1268
1269		for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
1270			rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packet, context, varyingLocColor, fragNdx));
1271	}
1272}
1273
1274std::string DrawTestShaderProgram::genVertexSource (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays)
1275{
1276	std::map<std::string, std::string>	params;
1277	std::stringstream					vertexShaderTmpl;
1278
1279	generateShaderParams(params, ctx.getType());
1280
1281	vertexShaderTmpl << "${VTX_HDR}";
1282
1283	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1284	{
1285		vertexShaderTmpl
1286			<< "${VTX_IN} highp " << outputTypeToGLType(arrays[arrayNdx]->getOutputType()) << " a_" << arrayNdx << ";\n";
1287	}
1288
1289	vertexShaderTmpl <<
1290		"uniform highp float u_coordScale;\n"
1291		"uniform highp float u_colorScale;\n"
1292		"${VTX_OUT} ${COL_PRECISION} vec4 v_color;\n"
1293		"void main(void)\n"
1294		"{\n"
1295		"\tgl_PointSize = 1.0;\n"
1296		"\thighp vec2 coord = vec2(0.0, 0.0);\n"
1297		"\thighp vec3 color = vec3(1.0, 1.0, 1.0);\n";
1298
1299	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1300	{
1301		const bool isPositionAttr = arrays[arrayNdx]->isPositionAttribute();
1302
1303		if (isPositionAttr)
1304		{
1305			switch (arrays[arrayNdx]->getOutputType())
1306			{
1307				case (DrawTestSpec::OUTPUTTYPE_FLOAT):
1308				case (DrawTestSpec::OUTPUTTYPE_INT):
1309				case (DrawTestSpec::OUTPUTTYPE_UINT):
1310					vertexShaderTmpl <<
1311						"\tcoord += vec2(float(a_" << arrayNdx << "), float(a_" << arrayNdx << "));\n";
1312					break;
1313
1314				case (DrawTestSpec::OUTPUTTYPE_VEC2):
1315				case (DrawTestSpec::OUTPUTTYPE_IVEC2):
1316				case (DrawTestSpec::OUTPUTTYPE_UVEC2):
1317					vertexShaderTmpl <<
1318						"\tcoord += vec2(a_" << arrayNdx << ".xy);\n";
1319					break;
1320
1321				case (DrawTestSpec::OUTPUTTYPE_VEC3):
1322				case (DrawTestSpec::OUTPUTTYPE_IVEC3):
1323				case (DrawTestSpec::OUTPUTTYPE_UVEC3):
1324					vertexShaderTmpl <<
1325						"\tcoord += vec2(a_" << arrayNdx << ".xy);\n"
1326						"\tcoord.x += float(a_" << arrayNdx << ".z);\n";
1327					break;
1328
1329				case (DrawTestSpec::OUTPUTTYPE_VEC4):
1330				case (DrawTestSpec::OUTPUTTYPE_IVEC4):
1331				case (DrawTestSpec::OUTPUTTYPE_UVEC4):
1332					vertexShaderTmpl <<
1333						"\tcoord += vec2(a_" << arrayNdx << ".xy);\n"
1334						"\tcoord += vec2(a_" << arrayNdx << ".zw);\n";
1335					break;
1336
1337				default:
1338					DE_ASSERT(false);
1339					break;
1340			}
1341		}
1342		else
1343		{
1344			switch (arrays[arrayNdx]->getOutputType())
1345			{
1346				case (DrawTestSpec::OUTPUTTYPE_FLOAT):
1347				case (DrawTestSpec::OUTPUTTYPE_INT):
1348				case (DrawTestSpec::OUTPUTTYPE_UINT):
1349					vertexShaderTmpl <<
1350						"\tcolor = color * float(a_" << arrayNdx << ");\n";
1351					break;
1352
1353				case (DrawTestSpec::OUTPUTTYPE_VEC2):
1354				case (DrawTestSpec::OUTPUTTYPE_IVEC2):
1355				case (DrawTestSpec::OUTPUTTYPE_UVEC2):
1356					vertexShaderTmpl <<
1357						"\tcolor.rg = color.rg * vec2(a_" << arrayNdx << ".xy);\n";
1358					break;
1359
1360				case (DrawTestSpec::OUTPUTTYPE_VEC3):
1361				case (DrawTestSpec::OUTPUTTYPE_IVEC3):
1362				case (DrawTestSpec::OUTPUTTYPE_UVEC3):
1363					vertexShaderTmpl <<
1364						"\tcolor = color.rgb * vec3(a_" << arrayNdx << ".xyz);\n";
1365					break;
1366
1367				case (DrawTestSpec::OUTPUTTYPE_VEC4):
1368				case (DrawTestSpec::OUTPUTTYPE_IVEC4):
1369				case (DrawTestSpec::OUTPUTTYPE_UVEC4):
1370					vertexShaderTmpl <<
1371						"\tcolor = color.rgb * vec3(a_" << arrayNdx << ".xyz) * float(a_" << arrayNdx << ".w);\n";
1372					break;
1373
1374				default:
1375					DE_ASSERT(false);
1376					break;
1377			}
1378		}
1379	}
1380
1381	vertexShaderTmpl <<
1382		"\tv_color = vec4(u_colorScale * color, 1.0) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5);\n"
1383		"\tgl_Position = vec4(u_coordScale * coord, 1.0, 1.0);\n"
1384		"}\n";
1385
1386	return tcu::StringTemplate(vertexShaderTmpl.str().c_str()).specialize(params);
1387}
1388
1389std::string DrawTestShaderProgram::genFragmentSource (const glu::RenderContext& ctx)
1390{
1391	std::map<std::string, std::string> params;
1392
1393	generateShaderParams(params, ctx.getType());
1394
1395	static const char* fragmentShaderTmpl =
1396		"${FRAG_HDR}"
1397		"${FRAG_IN} ${COL_PRECISION} vec4 v_color;\n"
1398		"void main(void)\n"
1399		"{\n"
1400		"\t${FRAG_COLOR} = v_color;\n"
1401		"}\n";
1402
1403	return tcu::StringTemplate(fragmentShaderTmpl).specialize(params);
1404}
1405
1406void DrawTestShaderProgram::generateShaderParams (std::map<std::string, std::string>& params, glu::ContextType type)
1407{
1408	if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_300_ES))
1409	{
1410		params["VTX_IN"]		= "in";
1411		params["VTX_OUT"]		= "out";
1412		params["FRAG_IN"]		= "in";
1413		params["FRAG_COLOR"]	= "dEQP_FragColor";
1414		params["VTX_HDR"]		= "#version 300 es\n";
1415		params["FRAG_HDR"]		= "#version 300 es\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1416		params["COL_PRECISION"]	= "mediump";
1417	}
1418	else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_100_ES))
1419	{
1420		params["VTX_IN"]		= "attribute";
1421		params["VTX_OUT"]		= "varying";
1422		params["FRAG_IN"]		= "varying";
1423		params["FRAG_COLOR"]	= "gl_FragColor";
1424		params["VTX_HDR"]		= "";
1425		params["FRAG_HDR"]		= "";
1426		params["COL_PRECISION"]	= "mediump";
1427	}
1428	else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_430))
1429	{
1430		params["VTX_IN"]		= "in";
1431		params["VTX_OUT"]		= "out";
1432		params["FRAG_IN"]		= "in";
1433		params["FRAG_COLOR"]	= "dEQP_FragColor";
1434		params["VTX_HDR"]		= "#version 430\n";
1435		params["FRAG_HDR"]		= "#version 430\nlayout(location = 0) out highp vec4 dEQP_FragColor;\n";
1436		params["COL_PRECISION"]	= "highp";
1437	}
1438	else if (glu::isGLSLVersionSupported(type, glu::GLSL_VERSION_330))
1439	{
1440		params["VTX_IN"]		= "in";
1441		params["VTX_OUT"]		= "out";
1442		params["FRAG_IN"]		= "in";
1443		params["FRAG_COLOR"]	= "dEQP_FragColor";
1444		params["VTX_HDR"]		= "#version 330\n";
1445		params["FRAG_HDR"]		= "#version 330\nlayout(location = 0) out mediump vec4 dEQP_FragColor;\n";
1446		params["COL_PRECISION"]	= "mediump";
1447	}
1448	else
1449		DE_ASSERT(DE_FALSE);
1450}
1451
1452rr::GenericVecType DrawTestShaderProgram::mapOutputType (const DrawTestSpec::OutputType& type)
1453{
1454	switch (type)
1455	{
1456		case (DrawTestSpec::OUTPUTTYPE_FLOAT):
1457		case (DrawTestSpec::OUTPUTTYPE_VEC2):
1458		case (DrawTestSpec::OUTPUTTYPE_VEC3):
1459		case (DrawTestSpec::OUTPUTTYPE_VEC4):
1460			return rr::GENERICVECTYPE_FLOAT;
1461
1462		case (DrawTestSpec::OUTPUTTYPE_INT):
1463		case (DrawTestSpec::OUTPUTTYPE_IVEC2):
1464		case (DrawTestSpec::OUTPUTTYPE_IVEC3):
1465		case (DrawTestSpec::OUTPUTTYPE_IVEC4):
1466			return rr::GENERICVECTYPE_INT32;
1467
1468		case (DrawTestSpec::OUTPUTTYPE_UINT):
1469		case (DrawTestSpec::OUTPUTTYPE_UVEC2):
1470		case (DrawTestSpec::OUTPUTTYPE_UVEC3):
1471		case (DrawTestSpec::OUTPUTTYPE_UVEC4):
1472			return rr::GENERICVECTYPE_UINT32;
1473
1474		default:
1475			DE_ASSERT(false);
1476			return rr::GENERICVECTYPE_LAST;
1477	}
1478}
1479
1480int DrawTestShaderProgram::getComponentCount (const DrawTestSpec::OutputType& type)
1481{
1482	switch (type)
1483	{
1484		case (DrawTestSpec::OUTPUTTYPE_FLOAT):
1485		case (DrawTestSpec::OUTPUTTYPE_INT):
1486		case (DrawTestSpec::OUTPUTTYPE_UINT):
1487			return 1;
1488
1489		case (DrawTestSpec::OUTPUTTYPE_VEC2):
1490		case (DrawTestSpec::OUTPUTTYPE_IVEC2):
1491		case (DrawTestSpec::OUTPUTTYPE_UVEC2):
1492			return 2;
1493
1494		case (DrawTestSpec::OUTPUTTYPE_VEC3):
1495		case (DrawTestSpec::OUTPUTTYPE_IVEC3):
1496		case (DrawTestSpec::OUTPUTTYPE_UVEC3):
1497			return 3;
1498
1499		case (DrawTestSpec::OUTPUTTYPE_VEC4):
1500		case (DrawTestSpec::OUTPUTTYPE_IVEC4):
1501		case (DrawTestSpec::OUTPUTTYPE_UVEC4):
1502			return 4;
1503
1504		default:
1505			DE_ASSERT(false);
1506			return 0;
1507	}
1508}
1509
1510sglr::pdec::ShaderProgramDeclaration DrawTestShaderProgram::createProgramDeclaration (const glu::RenderContext& ctx, const std::vector<AttributeArray*>& arrays)
1511{
1512	sglr::pdec::ShaderProgramDeclaration decl;
1513
1514	for (int arrayNdx = 0; arrayNdx < (int)arrays.size(); arrayNdx++)
1515		decl << sglr::pdec::VertexAttribute(std::string("a_") + de::toString(arrayNdx), mapOutputType(arrays[arrayNdx]->getOutputType()));
1516
1517	decl << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT);
1518	decl << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT);
1519
1520	decl << sglr::pdec::VertexSource(genVertexSource(ctx, arrays));
1521	decl << sglr::pdec::FragmentSource(genFragmentSource(ctx));
1522
1523	decl << sglr::pdec::Uniform("u_coordScale", glu::TYPE_FLOAT);
1524	decl << sglr::pdec::Uniform("u_colorScale", glu::TYPE_FLOAT);
1525
1526	return decl;
1527}
1528
1529class RandomArrayGenerator
1530{
1531public:
1532	static char*			generateArray			(int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type);
1533	static char*			generateIndices			(int seed, int elementCount, DrawTestSpec::IndexType type, int offset, int min, int max, int indexBase);
1534	static rr::GenericVec4	generateAttributeValue	(int seed, DrawTestSpec::InputType type);
1535
1536private:
1537	template<typename T>
1538	static char*			createIndices			(int seed, int elementCount, int offset, int min, int max, int indexBase);
1539	static void				setData					(char* data, DrawTestSpec::InputType type, deRandom& rnd, GLValue min, GLValue max);
1540
1541	static char*			generateBasicArray		(int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type);
1542	template<typename T, typename GLType>
1543	static char*			createBasicArray		(int seed, int elementCount, int componentCount, int offset, int stride);
1544	static char*			generatePackedArray		(int seed, int elementCount, int componentCount, int offset, int stride);
1545};
1546
1547void RandomArrayGenerator::setData (char* data, DrawTestSpec::InputType type, deRandom& rnd, GLValue min, GLValue max)
1548{
1549	switch (type)
1550	{
1551		case DrawTestSpec::INPUTTYPE_FLOAT:
1552		{
1553			alignmentSafeAssignment<float>(data, getRandom<GLValue::Float>(rnd, min.fl, max.fl));
1554			break;
1555		}
1556
1557		case DrawTestSpec::INPUTTYPE_SHORT:
1558		{
1559			alignmentSafeAssignment<deInt16>(data, getRandom<GLValue::Short>(rnd, min.s, max.s));
1560			break;
1561		}
1562
1563		case DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT:
1564		{
1565			alignmentSafeAssignment<deUint16>(data, getRandom<GLValue::Ushort>(rnd, min.us, max.us));
1566			break;
1567		}
1568
1569		case DrawTestSpec::INPUTTYPE_BYTE:
1570		{
1571			alignmentSafeAssignment<deInt8>(data, getRandom<GLValue::Byte>(rnd, min.b, max.b));
1572			break;
1573		}
1574
1575		case DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE:
1576		{
1577			alignmentSafeAssignment<deUint8>(data, getRandom<GLValue::Ubyte>(rnd, min.ub, max.ub));
1578			break;
1579		}
1580
1581		case DrawTestSpec::INPUTTYPE_FIXED:
1582		{
1583			alignmentSafeAssignment<deInt32>(data, getRandom<GLValue::Fixed>(rnd, min.fi, max.fi));
1584			break;
1585		}
1586
1587		case DrawTestSpec::INPUTTYPE_INT:
1588		{
1589			alignmentSafeAssignment<deInt32>(data, getRandom<GLValue::Int>(rnd, min.i, max.i));
1590			break;
1591		}
1592
1593		case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:
1594		{
1595			alignmentSafeAssignment<deUint32>(data, getRandom<GLValue::Uint>(rnd, min.ui, max.ui));
1596			break;
1597		}
1598
1599		case DrawTestSpec::INPUTTYPE_HALF:
1600		{
1601			alignmentSafeAssignment<deFloat16>(data, getRandom<GLValue::Half>(rnd, min.h, max.h).getValue());
1602			break;
1603		}
1604
1605		default:
1606			DE_ASSERT(false);
1607			break;
1608	}
1609}
1610
1611char* RandomArrayGenerator::generateArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type)
1612{
1613	if (type == DrawTestSpec::INPUTTYPE_INT_2_10_10_10 || type == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
1614		return generatePackedArray(seed, elementCount, componentCount, offset, stride);
1615	else
1616		return generateBasicArray(seed, elementCount, componentCount, offset, stride, type);
1617}
1618
1619char* RandomArrayGenerator::generateBasicArray (int seed, int elementCount, int componentCount, int offset, int stride, DrawTestSpec::InputType type)
1620{
1621	switch (type)
1622	{
1623		case DrawTestSpec::INPUTTYPE_FLOAT:				return createBasicArray<float,		GLValue::Float>	(seed, elementCount, componentCount, offset, stride);
1624		case DrawTestSpec::INPUTTYPE_DOUBLE:			return createBasicArray<double,		GLValue::Double>(seed, elementCount, componentCount, offset, stride);
1625		case DrawTestSpec::INPUTTYPE_SHORT:				return createBasicArray<deInt16,	GLValue::Short>	(seed, elementCount, componentCount, offset, stride);
1626		case DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT:	return createBasicArray<deUint16,	GLValue::Ushort>(seed, elementCount, componentCount, offset, stride);
1627		case DrawTestSpec::INPUTTYPE_BYTE:				return createBasicArray<deInt8,		GLValue::Byte>	(seed, elementCount, componentCount, offset, stride);
1628		case DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE:		return createBasicArray<deUint8,	GLValue::Ubyte>	(seed, elementCount, componentCount, offset, stride);
1629		case DrawTestSpec::INPUTTYPE_FIXED:				return createBasicArray<deInt32,	GLValue::Fixed>	(seed, elementCount, componentCount, offset, stride);
1630		case DrawTestSpec::INPUTTYPE_INT:				return createBasicArray<deInt32,	GLValue::Int>	(seed, elementCount, componentCount, offset, stride);
1631		case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:		return createBasicArray<deUint32,	GLValue::Uint>	(seed, elementCount, componentCount, offset, stride);
1632		case DrawTestSpec::INPUTTYPE_HALF:				return createBasicArray<deFloat16,	GLValue::Half>	(seed, elementCount, componentCount, offset, stride);
1633		default:
1634			DE_ASSERT(false);
1635			break;
1636	}
1637	return DE_NULL;
1638}
1639
1640#if (DE_COMPILER == DE_COMPILER_GCC) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)
1641	// GCC 4.8/4.9 incorrectly emits array-bounds warning from createBasicArray()
1642#	define GCC_ARRAY_BOUNDS_FALSE_NEGATIVE 1
1643#endif
1644
1645#if defined(GCC_ARRAY_BOUNDS_FALSE_NEGATIVE)
1646#	pragma GCC diagnostic push
1647#	pragma GCC diagnostic ignored "-Warray-bounds"
1648#endif
1649
1650template<typename T, typename GLType>
1651char* RandomArrayGenerator::createBasicArray (int seed, int elementCount, int componentCount, int offset, int stride)
1652{
1653	DE_ASSERT(componentCount >= 1 && componentCount <= 4);
1654
1655	const GLType min = extractGLValue<GLType>(GLValue::getMinValue(GLValueTypeTraits<GLType>::Type));
1656	const GLType max = extractGLValue<GLType>(GLValue::getMaxValue(GLValueTypeTraits<GLType>::Type));
1657
1658	const size_t componentSize	= sizeof(T);
1659	const size_t elementSize	= componentSize * componentCount;
1660	const size_t bufferSize		= offset + (elementCount - 1) * stride + elementSize;
1661
1662	char* data = new char[bufferSize];
1663	char* writePtr = data + offset;
1664
1665	GLType previousComponents[4];
1666
1667	deRandom rnd;
1668	deRandom_init(&rnd, seed);
1669
1670	for (int vertexNdx = 0; vertexNdx < elementCount; vertexNdx++)
1671	{
1672		GLType components[4];
1673
1674		for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1675		{
1676			components[componentNdx] = getRandom<GLType>(rnd, min, max);
1677
1678			// Try to not create vertex near previous
1679			if (vertexNdx != 0 && abs(components[componentNdx] - previousComponents[componentNdx]) < minValue<GLType>())
1680			{
1681				// Too close, try again (but only once)
1682				components[componentNdx] = getRandom<GLType>(rnd, min, max);
1683			}
1684		}
1685
1686		for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1687			previousComponents[componentNdx] = components[componentNdx];
1688
1689		for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1690			alignmentSafeAssignment(writePtr + componentNdx*componentSize, components[componentNdx].getValue());
1691
1692		writePtr += stride;
1693	}
1694
1695	return data;
1696}
1697
1698#if defined(GCC_ARRAY_BOUNDS_FALSE_NEGATIVE)
1699#	pragma GCC diagnostic pop
1700#endif
1701
1702char* RandomArrayGenerator::generatePackedArray (int seed, int elementCount, int componentCount, int offset, int stride)
1703{
1704	DE_ASSERT(componentCount == 4);
1705	DE_UNREF(componentCount);
1706
1707	const deUint32 limit10		= (1 << 10);
1708	const deUint32 limit2		= (1 << 2);
1709	const size_t elementSize	= 4;
1710	const size_t bufferSize		= offset + (elementCount - 1) * stride + elementSize;
1711
1712	char* data = new char[bufferSize];
1713	char* writePtr = data + offset;
1714
1715	deRandom rnd;
1716	deRandom_init(&rnd, seed);
1717
1718	for (int vertexNdx = 0; vertexNdx < elementCount; vertexNdx++)
1719	{
1720		const deUint32 x			= deRandom_getUint32(&rnd) % limit10;
1721		const deUint32 y			= deRandom_getUint32(&rnd) % limit10;
1722		const deUint32 z			= deRandom_getUint32(&rnd) % limit10;
1723		const deUint32 w			= deRandom_getUint32(&rnd) % limit2;
1724		const deUint32 packedValue	= (w << 30) | (z << 20) | (y << 10) | (x);
1725
1726		alignmentSafeAssignment(writePtr, packedValue);
1727		writePtr += stride;
1728	}
1729
1730	return data;
1731}
1732
1733char* RandomArrayGenerator::generateIndices (int seed, int elementCount, DrawTestSpec::IndexType type, int offset, int min, int max, int indexBase)
1734{
1735	char* data = DE_NULL;
1736
1737	switch (type)
1738	{
1739		case DrawTestSpec::INDEXTYPE_BYTE:
1740			data = createIndices<deUint8>(seed, elementCount, offset, min, max, indexBase);
1741			break;
1742
1743		case DrawTestSpec::INDEXTYPE_SHORT:
1744			data = createIndices<deUint16>(seed, elementCount, offset, min, max, indexBase);
1745			break;
1746
1747		case DrawTestSpec::INDEXTYPE_INT:
1748			data = createIndices<deUint32>(seed, elementCount, offset, min, max, indexBase);
1749			break;
1750
1751		default:
1752			DE_ASSERT(false);
1753			break;
1754	}
1755
1756	return data;
1757}
1758
1759template<typename T>
1760char* RandomArrayGenerator::createIndices (int seed, int elementCount, int offset, int min, int max, int indexBase)
1761{
1762	const size_t elementSize	= sizeof(T);
1763	const size_t bufferSize		= offset + elementCount * elementSize;
1764
1765	char* data = new char[bufferSize];
1766	char* writePtr = data + offset;
1767
1768	deUint32 oldNdx1 = deUint32(-1);
1769	deUint32 oldNdx2 = deUint32(-1);
1770
1771	deRandom rnd;
1772	deRandom_init(&rnd, seed);
1773
1774	DE_ASSERT(indexBase >= 0); // watch for underflows
1775
1776	if (min < 0 || (size_t)min > std::numeric_limits<T>::max() ||
1777		max < 0 || (size_t)max > std::numeric_limits<T>::max() ||
1778		min > max)
1779		DE_ASSERT(!"Invalid range");
1780
1781	for (int elementNdx = 0; elementNdx < elementCount; ++elementNdx)
1782	{
1783		deUint32 ndx = getRandom(rnd, GLValue::Uint::create(min), GLValue::Uint::create(max)).getValue();
1784
1785		// Try not to generate same index as any of previous two. This prevents
1786		// generation of degenerate triangles and lines. If [min, max] is too
1787		// small this cannot be guaranteed.
1788
1789		if (ndx == oldNdx1)			++ndx;
1790		if (ndx > (deUint32)max)	ndx = min;
1791		if (ndx == oldNdx2)			++ndx;
1792		if (ndx > (deUint32)max)	ndx = min;
1793		if (ndx == oldNdx1)			++ndx;
1794		if (ndx > (deUint32)max)	ndx = min;
1795
1796		oldNdx2 = oldNdx1;
1797		oldNdx1 = ndx;
1798
1799		ndx += indexBase;
1800
1801		alignmentSafeAssignment<T>(writePtr + elementSize * elementNdx, T(ndx));
1802	}
1803
1804	return data;
1805}
1806
1807rr::GenericVec4	RandomArrayGenerator::generateAttributeValue (int seed, DrawTestSpec::InputType type)
1808{
1809	de::Random random(seed);
1810
1811	switch (type)
1812	{
1813		case DrawTestSpec::INPUTTYPE_FLOAT:
1814			return rr::GenericVec4(generateRandomVec4(random));
1815
1816		case DrawTestSpec::INPUTTYPE_INT:
1817			return rr::GenericVec4(generateRandomIVec4(random));
1818
1819		case DrawTestSpec::INPUTTYPE_UNSIGNED_INT:
1820			return rr::GenericVec4(generateRandomUVec4(random));
1821
1822		default:
1823			DE_ASSERT(false);
1824			return rr::GenericVec4(tcu::Vec4(1, 1, 1, 1));
1825	}
1826}
1827
1828} // anonymous
1829
1830// AttributePack
1831
1832class AttributePack
1833{
1834public:
1835
1836								AttributePack		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, sglr::Context& drawContext, const tcu::UVec2& screenSize, bool useVao, bool logEnabled);
1837								~AttributePack		(void);
1838
1839	AttributeArray*				getArray			(int i);
1840	int							getArrayCount		(void);
1841
1842	void						newArray			(DrawTestSpec::Storage storage);
1843	void						clearArrays			(void);
1844	void 						updateProgram		(void);
1845
1846	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);
1847
1848	const tcu::Surface&			getSurface			(void) const { return m_screen; }
1849private:
1850	tcu::TestContext&			m_testCtx;
1851	glu::RenderContext&			m_renderCtx;
1852	sglr::Context&				m_ctx;
1853
1854	std::vector<AttributeArray*>m_arrays;
1855	sglr::ShaderProgram*		m_program;
1856	tcu::Surface				m_screen;
1857	const bool					m_useVao;
1858	const bool					m_logEnabled;
1859	deUint32					m_programID;
1860	deUint32					m_vaoID;
1861};
1862
1863AttributePack::AttributePack (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, sglr::Context& drawContext, const tcu::UVec2& screenSize, bool useVao, bool logEnabled)
1864	: m_testCtx		(testCtx)
1865	, m_renderCtx	(renderCtx)
1866	, m_ctx			(drawContext)
1867	, m_program		(DE_NULL)
1868	, m_screen		(screenSize.x(), screenSize.y())
1869	, m_useVao		(useVao)
1870	, m_logEnabled	(logEnabled)
1871	, m_programID	(0)
1872	, m_vaoID		(0)
1873{
1874	if (m_useVao)
1875		m_ctx.genVertexArrays(1, &m_vaoID);
1876}
1877
1878AttributePack::~AttributePack (void)
1879{
1880	clearArrays();
1881
1882	if (m_programID)
1883		m_ctx.deleteProgram(m_programID);
1884
1885	if (m_program)
1886		delete m_program;
1887
1888	if (m_useVao)
1889		m_ctx.deleteVertexArrays(1, &m_vaoID);
1890}
1891
1892AttributeArray* AttributePack::getArray (int i)
1893{
1894	return m_arrays.at(i);
1895}
1896
1897int AttributePack::getArrayCount (void)
1898{
1899	return (int)m_arrays.size();
1900}
1901
1902void AttributePack::newArray (DrawTestSpec::Storage storage)
1903{
1904	m_arrays.push_back(new AttributeArray(storage, m_ctx));
1905}
1906
1907void AttributePack::clearArrays (void)
1908{
1909	for (std::vector<AttributeArray*>::iterator itr = m_arrays.begin(); itr != m_arrays.end(); itr++)
1910		delete *itr;
1911	m_arrays.clear();
1912}
1913
1914void AttributePack::updateProgram (void)
1915{
1916	if (m_programID)
1917		m_ctx.deleteProgram(m_programID);
1918	if (m_program)
1919		delete m_program;
1920
1921	m_program = new DrawTestShaderProgram(m_renderCtx, m_arrays);
1922	m_programID = m_ctx.createProgram(m_program);
1923}
1924
1925void 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)
1926{
1927	DE_ASSERT(m_program != DE_NULL);
1928	DE_ASSERT(m_programID != 0);
1929
1930	m_ctx.viewport(0, 0, m_screen.getWidth(), m_screen.getHeight());
1931	m_ctx.clearColor(0.0, 0.0, 0.0, 1.0);
1932	m_ctx.clear(GL_COLOR_BUFFER_BIT);
1933
1934	m_ctx.useProgram(m_programID);
1935	GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glUseProgram()");
1936
1937	m_ctx.uniform1f(m_ctx.getUniformLocation(m_programID, "u_coordScale"), coordScale);
1938	m_ctx.uniform1f(m_ctx.getUniformLocation(m_programID, "u_colorScale"), colorScale);
1939
1940	if (m_useVao)
1941		m_ctx.bindVertexArray(m_vaoID);
1942
1943	if (indexArray)
1944		indexArray->bindIndexArray(DrawTestSpec::TARGET_ELEMENT_ARRAY);
1945
1946	for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
1947	{
1948		std::stringstream attribName;
1949		attribName << "a_" << arrayNdx;
1950
1951		deUint32 loc = m_ctx.getAttribLocation(m_programID, attribName.str().c_str());
1952
1953		if (m_arrays[arrayNdx]->isBound())
1954		{
1955			m_ctx.enableVertexAttribArray(loc);
1956			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glEnableVertexAttribArray()");
1957		}
1958
1959		m_arrays[arrayNdx]->bindAttribute(loc);
1960	}
1961
1962	if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS)
1963	{
1964		m_ctx.drawArrays(primitiveToGL(primitive), firstVertex, vertexCount);
1965		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArrays()");
1966	}
1967	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INSTANCED)
1968	{
1969		m_ctx.drawArraysInstanced(primitiveToGL(primitive), firstVertex, vertexCount, instanceCount);
1970		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysInstanced()");
1971	}
1972	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS)
1973	{
1974		m_ctx.drawElements(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset);
1975		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElements()");
1976	}
1977	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED)
1978	{
1979		m_ctx.drawRangeElements(primitiveToGL(primitive), rangeStart, rangeEnd, vertexCount, indexTypeToGL(indexType), indexOffset);
1980		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawRangeElements()");
1981	}
1982	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED)
1983	{
1984		m_ctx.drawElementsInstanced(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, instanceCount);
1985		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsInstanced()");
1986	}
1987	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWARRAYS_INDIRECT)
1988	{
1989		struct DrawCommand
1990		{
1991			GLuint count;
1992			GLuint primCount;
1993			GLuint first;
1994			GLuint reservedMustBeZero;
1995		};
1996		deUint8* buffer = new deUint8[sizeof(DrawCommand) + indirectOffset];
1997
1998		{
1999			DrawCommand command;
2000
2001			command.count				= vertexCount;
2002			command.primCount			= instanceCount;
2003			command.first				= firstVertex;
2004			command.reservedMustBeZero	= 0;
2005
2006			memcpy(buffer + indirectOffset, &command, sizeof(command));
2007
2008			if (m_logEnabled)
2009				m_testCtx.getLog()
2010					<< tcu::TestLog::Message
2011					<< "DrawArraysIndirectCommand:\n"
2012					<< "\tcount: " << command.count << "\n"
2013					<< "\tprimCount: " << command.primCount << "\n"
2014					<< "\tfirst: " << command.first << "\n"
2015					<< "\treservedMustBeZero: " << command.reservedMustBeZero << "\n"
2016					<< tcu::TestLog::EndMessage;
2017		}
2018
2019		GLuint indirectBuf = 0;
2020		m_ctx.genBuffers(1, &indirectBuf);
2021		m_ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf);
2022		m_ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand) + indirectOffset, buffer, GL_STATIC_DRAW);
2023		delete [] buffer;
2024
2025		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "Setup draw indirect buffer");
2026
2027		m_ctx.drawArraysIndirect(primitiveToGL(primitive), (const deInt8*)DE_NULL + indirectOffset);
2028		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysIndirect()");
2029
2030		m_ctx.deleteBuffers(1, &indirectBuf);
2031	}
2032	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INDIRECT)
2033	{
2034		struct DrawCommand
2035		{
2036			GLuint count;
2037			GLuint primCount;
2038			GLuint firstIndex;
2039			GLint  baseVertex;
2040			GLuint reservedMustBeZero;
2041		};
2042		deUint8* buffer = new deUint8[sizeof(DrawCommand) + indirectOffset];
2043
2044		{
2045			DrawCommand command;
2046
2047			// index offset must be converted to firstIndex by dividing with the index element size
2048			DE_ASSERT(((const deUint8*)indexOffset - (const deUint8*)DE_NULL) % gls::DrawTestSpec::indexTypeSize(indexType) == 0); // \note This is checked in spec validation
2049
2050			command.count				= vertexCount;
2051			command.primCount			= instanceCount;
2052			command.firstIndex			= (glw::GLuint)(((const deUint8*)indexOffset - (const deUint8*)DE_NULL) / gls::DrawTestSpec::indexTypeSize(indexType));
2053			command.baseVertex			= baseVertex;
2054			command.reservedMustBeZero	= 0;
2055
2056			memcpy(buffer + indirectOffset, &command, sizeof(command));
2057
2058			if (m_logEnabled)
2059				m_testCtx.getLog()
2060					<< tcu::TestLog::Message
2061					<< "DrawElementsIndirectCommand:\n"
2062					<< "\tcount: " << command.count << "\n"
2063					<< "\tprimCount: " << command.primCount << "\n"
2064					<< "\tfirstIndex: " << command.firstIndex << "\n"
2065					<< "\tbaseVertex: " << command.baseVertex << "\n"
2066					<< "\treservedMustBeZero: " << command.reservedMustBeZero << "\n"
2067					<< tcu::TestLog::EndMessage;
2068		}
2069
2070		GLuint indirectBuf = 0;
2071		m_ctx.genBuffers(1, &indirectBuf);
2072		m_ctx.bindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf);
2073		m_ctx.bufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand) + indirectOffset, buffer, GL_STATIC_DRAW);
2074		delete [] buffer;
2075
2076		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "Setup draw indirect buffer");
2077
2078		m_ctx.drawElementsIndirect(primitiveToGL(primitive), indexTypeToGL(indexType), (const deInt8*)DE_NULL + indirectOffset);
2079		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawArraysIndirect()");
2080
2081		m_ctx.deleteBuffers(1, &indirectBuf);
2082	}
2083	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_BASEVERTEX)
2084	{
2085		m_ctx.drawElementsBaseVertex(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, baseVertex);
2086		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsBaseVertex()");
2087	}
2088	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX)
2089	{
2090		m_ctx.drawElementsInstancedBaseVertex(primitiveToGL(primitive), vertexCount, indexTypeToGL(indexType), indexOffset, instanceCount, baseVertex);
2091		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawElementsInstancedBaseVertex()");
2092	}
2093	else if (drawMethod == DrawTestSpec::DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX)
2094	{
2095		m_ctx.drawRangeElementsBaseVertex(primitiveToGL(primitive), rangeStart, rangeEnd, vertexCount, indexTypeToGL(indexType), indexOffset, baseVertex);
2096		GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDrawRangeElementsBaseVertex()");
2097	}
2098	else
2099		DE_ASSERT(DE_FALSE);
2100
2101	for (int arrayNdx = 0; arrayNdx < (int)m_arrays.size(); arrayNdx++)
2102	{
2103		if (m_arrays[arrayNdx]->isBound())
2104		{
2105			std::stringstream attribName;
2106			attribName << "a_" << arrayNdx;
2107
2108			deUint32 loc = m_ctx.getAttribLocation(m_programID, attribName.str().c_str());
2109
2110			m_ctx.disableVertexAttribArray(loc);
2111			GLU_EXPECT_NO_ERROR(m_ctx.getError(), "glDisableVertexAttribArray()");
2112		}
2113	}
2114
2115	if (m_useVao)
2116		m_ctx.bindVertexArray(0);
2117
2118	m_ctx.useProgram(0);
2119	m_ctx.readPixels(m_screen, 0, 0, m_screen.getWidth(), m_screen.getHeight());
2120}
2121
2122// DrawTestSpec
2123
2124DrawTestSpec::AttributeSpec	DrawTestSpec::AttributeSpec::createAttributeArray (InputType inputType, OutputType outputType, Storage storage, Usage usage, int componentCount, int offset, int stride, bool normalize, int instanceDivisor)
2125{
2126	DrawTestSpec::AttributeSpec spec;
2127
2128	spec.inputType			= inputType;
2129	spec.outputType			= outputType;
2130	spec.storage			= storage;
2131	spec.usage				= usage;
2132	spec.componentCount		= componentCount;
2133	spec.offset				= offset;
2134	spec.stride				= stride;
2135	spec.normalize			= normalize;
2136	spec.instanceDivisor	= instanceDivisor;
2137
2138	spec.useDefaultAttribute= false;
2139
2140	return spec;
2141}
2142
2143DrawTestSpec::AttributeSpec	DrawTestSpec::AttributeSpec::createDefaultAttribute (InputType inputType, OutputType outputType, int componentCount)
2144{
2145	DE_ASSERT(inputType == INPUTTYPE_INT || inputType == INPUTTYPE_UNSIGNED_INT || inputType == INPUTTYPE_FLOAT);
2146	DE_ASSERT(inputType == INPUTTYPE_FLOAT || componentCount == 4);
2147
2148	DrawTestSpec::AttributeSpec spec;
2149
2150	spec.inputType				= inputType;
2151	spec.outputType				= outputType;
2152	spec.storage				= DrawTestSpec::STORAGE_LAST;
2153	spec.usage					= DrawTestSpec::USAGE_LAST;
2154	spec.componentCount			= componentCount;
2155	spec.offset					= 0;
2156	spec.stride					= 0;
2157	spec.normalize				= 0;
2158	spec.instanceDivisor		= 0;
2159
2160	spec.useDefaultAttribute	= true;
2161
2162	return spec;
2163}
2164
2165DrawTestSpec::AttributeSpec::AttributeSpec (void)
2166{
2167	inputType					= DrawTestSpec::INPUTTYPE_LAST;
2168	outputType					= DrawTestSpec::OUTPUTTYPE_LAST;
2169	storage						= DrawTestSpec::STORAGE_LAST;
2170	usage						= DrawTestSpec::USAGE_LAST;
2171	componentCount				= 0;
2172	offset						= 0;
2173	stride						= 0;
2174	normalize					= false;
2175	instanceDivisor				= 0;
2176	useDefaultAttribute			= false;
2177	additionalPositionAttribute = false;
2178	bgraComponentOrder			= false;
2179}
2180
2181int DrawTestSpec::AttributeSpec::hash (void) const
2182{
2183	if (useDefaultAttribute)
2184	{
2185		return 1 * int(inputType) + 7 * int(outputType) + 13 * componentCount;
2186	}
2187	else
2188	{
2189		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;
2190	}
2191}
2192
2193bool DrawTestSpec::AttributeSpec::valid (glu::ApiType ctxType) const
2194{
2195	const bool inputTypeFloat				= inputType == DrawTestSpec::INPUTTYPE_FLOAT || inputType  == DrawTestSpec::INPUTTYPE_FIXED || inputType == DrawTestSpec::INPUTTYPE_HALF;
2196	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;
2197	const bool inputTypeSignedInteger		= inputType == DrawTestSpec::INPUTTYPE_BYTE  || inputType == DrawTestSpec::INPUTTYPE_SHORT || inputType == DrawTestSpec::INPUTTYPE_INT || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
2198	const bool inputTypePacked				= inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
2199
2200	const bool outputTypeFloat				= outputType == DrawTestSpec::OUTPUTTYPE_FLOAT || outputType == DrawTestSpec::OUTPUTTYPE_VEC2  || outputType == DrawTestSpec::OUTPUTTYPE_VEC3  || outputType == DrawTestSpec::OUTPUTTYPE_VEC4;
2201	const bool outputTypeSignedInteger		= outputType == DrawTestSpec::OUTPUTTYPE_INT   || outputType == DrawTestSpec::OUTPUTTYPE_IVEC2 || outputType == DrawTestSpec::OUTPUTTYPE_IVEC3 || outputType == DrawTestSpec::OUTPUTTYPE_IVEC4;
2202	const bool outputTypeUnsignedInteger	= outputType == DrawTestSpec::OUTPUTTYPE_UINT  || outputType == DrawTestSpec::OUTPUTTYPE_UVEC2 || outputType == DrawTestSpec::OUTPUTTYPE_UVEC3 || outputType == DrawTestSpec::OUTPUTTYPE_UVEC4;
2203
2204	if (useDefaultAttribute)
2205	{
2206		if (inputType != DrawTestSpec::INPUTTYPE_INT && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT && inputType != DrawTestSpec::INPUTTYPE_FLOAT)
2207			return false;
2208
2209		if (inputType != DrawTestSpec::INPUTTYPE_FLOAT && componentCount != 4)
2210			return false;
2211
2212		// no casting allowed (undefined results)
2213		if (inputType == DrawTestSpec::INPUTTYPE_INT && !outputTypeSignedInteger)
2214			return false;
2215		if (inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT && !outputTypeUnsignedInteger)
2216			return false;
2217	}
2218
2219	if (inputTypePacked && componentCount != 4)
2220		return false;
2221
2222	// Invalid conversions:
2223
2224	// float -> [u]int
2225	if (inputTypeFloat && !outputTypeFloat)
2226		return false;
2227
2228	// uint -> int		(undefined results)
2229	if (inputTypeUnsignedInteger && outputTypeSignedInteger)
2230		return false;
2231
2232	// int -> uint		(undefined results)
2233	if (inputTypeSignedInteger && outputTypeUnsignedInteger)
2234		return false;
2235
2236	// packed -> non-float (packed formats are converted to floats)
2237	if (inputTypePacked && !outputTypeFloat)
2238		return false;
2239
2240	// Invalid normalize. Normalize is only valid if output type is float
2241	if (normalize && !outputTypeFloat)
2242		return false;
2243
2244	// Allow reverse order (GL_BGRA) only for packed and 4-component ubyte
2245	if (bgraComponentOrder && componentCount != 4)
2246		return false;
2247	if (bgraComponentOrder && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && inputType != DrawTestSpec::INPUTTYPE_INT_2_10_10_10 && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE)
2248		return false;
2249	if (bgraComponentOrder && normalize != true)
2250		return false;
2251
2252	// GLES2 limits
2253	if (ctxType == glu::ApiType::es(2,0))
2254	{
2255		if (inputType != DrawTestSpec::INPUTTYPE_FLOAT && inputType != DrawTestSpec::INPUTTYPE_FIXED &&
2256			inputType != DrawTestSpec::INPUTTYPE_BYTE  && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_BYTE &&
2257			inputType != DrawTestSpec::INPUTTYPE_SHORT && inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_SHORT)
2258			return false;
2259
2260		if (!outputTypeFloat)
2261			return false;
2262
2263		if (bgraComponentOrder)
2264			return false;
2265	}
2266
2267	// GLES3 limits
2268	if (ctxType.getProfile() == glu::PROFILE_ES && ctxType.getMajorVersion() == 3)
2269	{
2270		if (bgraComponentOrder)
2271			return false;
2272	}
2273
2274	// No user pointers in GL core
2275	if (ctxType.getProfile() == glu::PROFILE_CORE)
2276	{
2277		if (!useDefaultAttribute && storage == DrawTestSpec::STORAGE_USER)
2278			return false;
2279	}
2280
2281	return true;
2282}
2283
2284bool DrawTestSpec::AttributeSpec::isBufferAligned (void) const
2285{
2286	const bool inputTypePacked = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
2287
2288	// Buffer alignment, offset is a multiple of underlying data type size?
2289	if (storage == STORAGE_BUFFER)
2290	{
2291		int dataTypeSize = gls::DrawTestSpec::inputTypeSize(inputType);
2292		if (inputTypePacked)
2293			dataTypeSize = 4;
2294
2295		if (offset % dataTypeSize != 0)
2296			return false;
2297	}
2298
2299	return true;
2300}
2301
2302bool DrawTestSpec::AttributeSpec::isBufferStrideAligned (void) const
2303{
2304	const bool inputTypePacked = inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 || inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10;
2305
2306	// Buffer alignment, offset is a multiple of underlying data type size?
2307	if (storage == STORAGE_BUFFER)
2308	{
2309		int dataTypeSize = gls::DrawTestSpec::inputTypeSize(inputType);
2310		if (inputTypePacked)
2311			dataTypeSize = 4;
2312
2313		if (stride % dataTypeSize != 0)
2314			return false;
2315	}
2316
2317	return true;
2318}
2319
2320std::string DrawTestSpec::targetToString(Target target)
2321{
2322	static const char* targets[] =
2323	{
2324		"element_array",	// TARGET_ELEMENT_ARRAY = 0,
2325		"array"				// TARGET_ARRAY,
2326	};
2327
2328	return de::getSizedArrayElement<DrawTestSpec::TARGET_LAST>(targets, (int)target);
2329}
2330
2331std::string DrawTestSpec::inputTypeToString(InputType type)
2332{
2333	static const char* types[] =
2334	{
2335		"float",			// INPUTTYPE_FLOAT = 0,
2336		"fixed",			// INPUTTYPE_FIXED,
2337		"double",			// INPUTTYPE_DOUBLE
2338
2339		"byte",				// INPUTTYPE_BYTE,
2340		"short",			// INPUTTYPE_SHORT,
2341
2342		"unsigned_byte",	// INPUTTYPE_UNSIGNED_BYTE,
2343		"unsigned_short",	// INPUTTYPE_UNSIGNED_SHORT,
2344
2345		"int",						// INPUTTYPE_INT,
2346		"unsigned_int",				// INPUTTYPE_UNSIGNED_INT,
2347		"half",						// INPUTTYPE_HALF,
2348		"unsigned_int2_10_10_10",	// INPUTTYPE_UNSIGNED_INT_2_10_10_10,
2349		"int2_10_10_10"				// INPUTTYPE_INT_2_10_10_10,
2350	};
2351
2352	return de::getSizedArrayElement<DrawTestSpec::INPUTTYPE_LAST>(types, (int)type);
2353}
2354
2355std::string DrawTestSpec::outputTypeToString(OutputType type)
2356{
2357	static const char* types[] =
2358	{
2359		"float",		// OUTPUTTYPE_FLOAT = 0,
2360		"vec2",			// OUTPUTTYPE_VEC2,
2361		"vec3",			// OUTPUTTYPE_VEC3,
2362		"vec4",			// OUTPUTTYPE_VEC4,
2363
2364		"int",			// OUTPUTTYPE_INT,
2365		"uint",			// OUTPUTTYPE_UINT,
2366
2367		"ivec2",		// OUTPUTTYPE_IVEC2,
2368		"ivec3",		// OUTPUTTYPE_IVEC3,
2369		"ivec4",		// OUTPUTTYPE_IVEC4,
2370
2371		"uvec2",		// OUTPUTTYPE_UVEC2,
2372		"uvec3",		// OUTPUTTYPE_UVEC3,
2373		"uvec4",		// OUTPUTTYPE_UVEC4,
2374	};
2375
2376	return de::getSizedArrayElement<DrawTestSpec::OUTPUTTYPE_LAST>(types, (int)type);
2377}
2378
2379std::string DrawTestSpec::usageTypeToString(Usage usage)
2380{
2381	static const char* usages[] =
2382	{
2383		"dynamic_draw",	// USAGE_DYNAMIC_DRAW = 0,
2384		"static_draw",	// USAGE_STATIC_DRAW,
2385		"stream_draw",	// USAGE_STREAM_DRAW,
2386
2387		"stream_read",	// USAGE_STREAM_READ,
2388		"stream_copy",	// USAGE_STREAM_COPY,
2389
2390		"static_read",	// USAGE_STATIC_READ,
2391		"static_copy",	// USAGE_STATIC_COPY,
2392
2393		"dynamic_read",	// USAGE_DYNAMIC_READ,
2394		"dynamic_copy",	// USAGE_DYNAMIC_COPY,
2395	};
2396
2397	return de::getSizedArrayElement<DrawTestSpec::USAGE_LAST>(usages, (int)usage);
2398}
2399
2400std::string	DrawTestSpec::storageToString (Storage storage)
2401{
2402	static const char* storages[] =
2403	{
2404		"user_ptr",	// STORAGE_USER = 0,
2405		"buffer"	// STORAGE_BUFFER,
2406	};
2407
2408	return de::getSizedArrayElement<DrawTestSpec::STORAGE_LAST>(storages, (int)storage);
2409}
2410
2411std::string DrawTestSpec::primitiveToString (Primitive primitive)
2412{
2413	static const char* primitives[] =
2414	{
2415		"points",					// PRIMITIVE_POINTS ,
2416		"triangles",				// PRIMITIVE_TRIANGLES,
2417		"triangle_fan",				// PRIMITIVE_TRIANGLE_FAN,
2418		"triangle_strip",			// PRIMITIVE_TRIANGLE_STRIP,
2419		"lines",					// PRIMITIVE_LINES
2420		"line_strip",				// PRIMITIVE_LINE_STRIP
2421		"line_loop",				// PRIMITIVE_LINE_LOOP
2422		"lines_adjacency",			// PRIMITIVE_LINES_ADJACENCY
2423		"line_strip_adjacency",		// PRIMITIVE_LINE_STRIP_ADJACENCY
2424		"triangles_adjacency",		// PRIMITIVE_TRIANGLES_ADJACENCY
2425		"triangle_strip_adjacency",	// PRIMITIVE_TRIANGLE_STRIP_ADJACENCY
2426	};
2427
2428	return de::getSizedArrayElement<DrawTestSpec::PRIMITIVE_LAST>(primitives, (int)primitive);
2429}
2430
2431std::string DrawTestSpec::indexTypeToString (IndexType type)
2432{
2433	static const char* indexTypes[] =
2434	{
2435		"byte",		// INDEXTYPE_BYTE = 0,
2436		"short",	// INDEXTYPE_SHORT,
2437		"int",		// INDEXTYPE_INT,
2438	};
2439
2440	return de::getSizedArrayElement<DrawTestSpec::INDEXTYPE_LAST>(indexTypes, (int)type);
2441}
2442
2443std::string DrawTestSpec::drawMethodToString (DrawTestSpec::DrawMethod method)
2444{
2445	static const char* methods[] =
2446	{
2447		"draw_arrays",							//!< DRAWMETHOD_DRAWARRAYS
2448		"draw_arrays_instanced",				//!< DRAWMETHOD_DRAWARRAYS_INSTANCED
2449		"draw_arrays_indirect",					//!< DRAWMETHOD_DRAWARRAYS_INDIRECT
2450		"draw_elements",						//!< DRAWMETHOD_DRAWELEMENTS
2451		"draw_range_elements",					//!< DRAWMETHOD_DRAWELEMENTS_RANGED
2452		"draw_elements_instanced",				//!< DRAWMETHOD_DRAWELEMENTS_INSTANCED
2453		"draw_elements_indirect",				//!< DRAWMETHOD_DRAWELEMENTS_INDIRECT
2454		"draw_elements_base_vertex",			//!< DRAWMETHOD_DRAWELEMENTS_BASEVERTEX,
2455		"draw_elements_instanced_base_vertex",	//!< DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX,
2456		"draw_range_elements_base_vertex",		//!< DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX,
2457	};
2458
2459	return de::getSizedArrayElement<DrawTestSpec::DRAWMETHOD_LAST>(methods, (int)method);
2460}
2461
2462int DrawTestSpec::inputTypeSize (InputType type)
2463{
2464	static const int size[] =
2465	{
2466		sizeof(float),		// INPUTTYPE_FLOAT = 0,
2467		sizeof(deInt32),	// INPUTTYPE_FIXED,
2468		sizeof(double),		// INPUTTYPE_DOUBLE
2469
2470		sizeof(deInt8),		// INPUTTYPE_BYTE,
2471		sizeof(deInt16),	// INPUTTYPE_SHORT,
2472
2473		sizeof(deUint8),	// INPUTTYPE_UNSIGNED_BYTE,
2474		sizeof(deUint16),	// INPUTTYPE_UNSIGNED_SHORT,
2475
2476		sizeof(deInt32),		// INPUTTYPE_INT,
2477		sizeof(deUint32),		// INPUTTYPE_UNSIGNED_INT,
2478		sizeof(deFloat16),		// INPUTTYPE_HALF,
2479		sizeof(deUint32) / 4,		// INPUTTYPE_UNSIGNED_INT_2_10_10_10,
2480		sizeof(deUint32) / 4		// INPUTTYPE_INT_2_10_10_10,
2481	};
2482
2483	return de::getSizedArrayElement<DrawTestSpec::INPUTTYPE_LAST>(size, (int)type);
2484}
2485
2486int DrawTestSpec::indexTypeSize (IndexType type)
2487{
2488	static const int size[] =
2489	{
2490		sizeof(deUint8),	// INDEXTYPE_BYTE,
2491		sizeof(deUint16),	// INDEXTYPE_SHORT,
2492		sizeof(deUint32),	// INDEXTYPE_INT,
2493	};
2494
2495	return de::getSizedArrayElement<DrawTestSpec::INDEXTYPE_LAST>(size, (int)type);
2496}
2497
2498std::string DrawTestSpec::getName (void) const
2499{
2500	const MethodInfo	methodInfo	= getMethodInfo(drawMethod);
2501	const bool			hasFirst	= methodInfo.first;
2502	const bool			instanced	= methodInfo.instanced;
2503	const bool			ranged		= methodInfo.ranged;
2504	const bool			indexed		= methodInfo.indexed;
2505
2506	std::stringstream name;
2507
2508	for (size_t ndx = 0; ndx < attribs.size(); ++ndx)
2509	{
2510		const AttributeSpec& attrib = attribs[ndx];
2511
2512		if (attribs.size() > 1)
2513			name << "attrib" << ndx << "_";
2514
2515		if (ndx == 0|| attrib.additionalPositionAttribute)
2516			name << "pos_";
2517		else
2518			name << "col_";
2519
2520		if (attrib.useDefaultAttribute)
2521		{
2522			name
2523				<< "non_array_"
2524				<< DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "_"
2525				<< attrib.componentCount << "_"
2526				<< DrawTestSpec::outputTypeToString(attrib.outputType) << "_";
2527		}
2528		else
2529		{
2530			name
2531				<< DrawTestSpec::storageToString(attrib.storage) << "_"
2532				<< attrib.offset << "_"
2533				<< attrib.stride << "_"
2534				<< DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType);
2535			if (attrib.inputType != DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10 && attrib.inputType != DrawTestSpec::INPUTTYPE_INT_2_10_10_10)
2536				name << attrib.componentCount;
2537			name
2538				<< "_"
2539				<< (attrib.normalize ? "normalized_" : "")
2540				<< DrawTestSpec::outputTypeToString(attrib.outputType) << "_"
2541				<< DrawTestSpec::usageTypeToString(attrib.usage) << "_"
2542				<< attrib.instanceDivisor << "_";
2543		}
2544	}
2545
2546	if (indexed)
2547		name
2548			<< "index_" << DrawTestSpec::indexTypeToString(indexType) << "_"
2549			<< DrawTestSpec::storageToString(indexStorage) << "_"
2550			<< "offset" << indexPointerOffset << "_";
2551	if (hasFirst)
2552		name << "first" << first << "_";
2553	if (ranged)
2554		name << "ranged_" << indexMin << "_" << indexMax << "_";
2555	if (instanced)
2556		name << "instances" << instanceCount << "_";
2557
2558	switch (primitive)
2559	{
2560		case DrawTestSpec::PRIMITIVE_POINTS:
2561			name << "points_";
2562			break;
2563		case DrawTestSpec::PRIMITIVE_TRIANGLES:
2564			name << "triangles_";
2565			break;
2566		case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
2567			name << "triangle_fan_";
2568			break;
2569		case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
2570			name << "triangle_strip_";
2571			break;
2572		case DrawTestSpec::PRIMITIVE_LINES:
2573			name << "lines_";
2574			break;
2575		case DrawTestSpec::PRIMITIVE_LINE_STRIP:
2576			name << "line_strip_";
2577			break;
2578		case DrawTestSpec::PRIMITIVE_LINE_LOOP:
2579			name << "line_loop_";
2580			break;
2581		case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
2582			name << "line_adjancency";
2583			break;
2584		case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
2585			name << "line_strip_adjancency";
2586			break;
2587		case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
2588			name << "triangles_adjancency";
2589			break;
2590		case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
2591			name << "triangle_strip_adjancency";
2592			break;
2593		default:
2594			DE_ASSERT(false);
2595			break;
2596	}
2597
2598	name << primitiveCount;
2599
2600	return name.str();
2601}
2602
2603std::string DrawTestSpec::getDesc (void) const
2604{
2605	std::stringstream desc;
2606
2607	for (size_t ndx = 0; ndx < attribs.size(); ++ndx)
2608	{
2609		const AttributeSpec& attrib = attribs[ndx];
2610
2611		if (attrib.useDefaultAttribute)
2612		{
2613			desc
2614				<< "Attribute " << ndx << ": default, " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position ,") : ("color ,"))
2615				<< "input datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << ", "
2616				<< "input component count " << attrib.componentCount << ", "
2617				<< "used as " << DrawTestSpec::outputTypeToString(attrib.outputType) << ", ";
2618		}
2619		else
2620		{
2621			desc
2622				<< "Attribute " << ndx << ": " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position ,") : ("color ,"))
2623				<< "Storage in " << DrawTestSpec::storageToString(attrib.storage) << ", "
2624				<< "stride " << attrib.stride << ", "
2625				<< "input datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << ", "
2626				<< "input component count " << attrib.componentCount << ", "
2627				<< (attrib.normalize ? "normalized, " : "")
2628				<< "used as " << DrawTestSpec::outputTypeToString(attrib.outputType) << ", "
2629				<< "instance divisor " << attrib.instanceDivisor << ", ";
2630		}
2631	}
2632
2633	if (drawMethod == DRAWMETHOD_DRAWARRAYS)
2634	{
2635		desc
2636			<< "drawArrays(), "
2637			<< "first " << first << ", ";
2638	}
2639	else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INSTANCED)
2640	{
2641		desc
2642			<< "drawArraysInstanced(), "
2643			<< "first " << first << ", "
2644			<< "instance count " << instanceCount << ", ";
2645	}
2646	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS)
2647	{
2648		desc
2649			<< "drawElements(), "
2650			<< "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
2651			<< "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
2652			<< "index offset " << indexPointerOffset << ", ";
2653	}
2654	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED)
2655	{
2656		desc
2657			<< "drawElementsRanged(), "
2658			<< "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
2659			<< "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
2660			<< "index offset " << indexPointerOffset << ", "
2661			<< "range start " << indexMin << ", "
2662			<< "range end " << indexMax << ", ";
2663	}
2664	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED)
2665	{
2666		desc
2667			<< "drawElementsInstanced(), "
2668			<< "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
2669			<< "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
2670			<< "index offset " << indexPointerOffset << ", "
2671			<< "instance count " << instanceCount << ", ";
2672	}
2673	else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INDIRECT)
2674	{
2675		desc
2676			<< "drawArraysIndirect(), "
2677			<< "first " << first << ", "
2678			<< "instance count " << instanceCount << ", "
2679			<< "indirect offset " << indirectOffset << ", ";
2680	}
2681	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT)
2682	{
2683		desc
2684			<< "drawElementsIndirect(), "
2685			<< "index type " << DrawTestSpec::indexTypeToString(indexType) << ", "
2686			<< "index storage in " << DrawTestSpec::storageToString(indexStorage) << ", "
2687			<< "index offset " << indexPointerOffset << ", "
2688			<< "instance count " << instanceCount << ", "
2689			<< "indirect offset " << indirectOffset << ", "
2690			<< "base vertex " << baseVertex << ", ";
2691	}
2692	else
2693		DE_ASSERT(DE_FALSE);
2694
2695	desc << primitiveCount;
2696
2697	switch (primitive)
2698	{
2699		case DrawTestSpec::PRIMITIVE_POINTS:
2700			desc << "points";
2701			break;
2702		case DrawTestSpec::PRIMITIVE_TRIANGLES:
2703			desc << "triangles";
2704			break;
2705		case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
2706			desc << "triangles (fan)";
2707			break;
2708		case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
2709			desc << "triangles (strip)";
2710			break;
2711		case DrawTestSpec::PRIMITIVE_LINES:
2712			desc << "lines";
2713			break;
2714		case DrawTestSpec::PRIMITIVE_LINE_STRIP:
2715			desc << "lines (strip)";
2716			break;
2717		case DrawTestSpec::PRIMITIVE_LINE_LOOP:
2718			desc << "lines (loop)";
2719			break;
2720		case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
2721			desc << "lines (adjancency)";
2722			break;
2723		case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
2724			desc << "lines (strip, adjancency)";
2725			break;
2726		case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
2727			desc << "triangles (adjancency)";
2728			break;
2729		case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
2730			desc << "triangles (strip, adjancency)";
2731			break;
2732		default:
2733			DE_ASSERT(false);
2734			break;
2735	}
2736
2737	return desc.str();
2738}
2739
2740std::string DrawTestSpec::getMultilineDesc (void) const
2741{
2742	std::stringstream desc;
2743
2744	for (size_t ndx = 0; ndx < attribs.size(); ++ndx)
2745	{
2746		const AttributeSpec& attrib = attribs[ndx];
2747
2748		if (attrib.useDefaultAttribute)
2749		{
2750			desc
2751				<< "Attribute " << ndx << ": default, " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position\n") : ("color\n"))
2752				<< "\tinput datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "\n"
2753				<< "\tinput component count " << attrib.componentCount << "\n"
2754				<< "\tused as " << DrawTestSpec::outputTypeToString(attrib.outputType) << "\n";
2755		}
2756		else
2757		{
2758			desc
2759				<< "Attribute " << ndx << ": " << ((ndx == 0|| attrib.additionalPositionAttribute) ? ("position\n") : ("color\n"))
2760				<< "\tStorage in " << DrawTestSpec::storageToString(attrib.storage) << "\n"
2761				<< "\tstride " << attrib.stride << "\n"
2762				<< "\tinput datatype " << DrawTestSpec::inputTypeToString((DrawTestSpec::InputType)attrib.inputType) << "\n"
2763				<< "\tinput component count " << attrib.componentCount << "\n"
2764				<< (attrib.normalize ? "\tnormalized\n" : "")
2765				<< "\tused as " << DrawTestSpec::outputTypeToString(attrib.outputType) << "\n"
2766				<< "\tinstance divisor " << attrib.instanceDivisor << "\n";
2767		}
2768	}
2769
2770	if (drawMethod == DRAWMETHOD_DRAWARRAYS)
2771	{
2772		desc
2773			<< "drawArrays()\n"
2774			<< "\tfirst " << first << "\n";
2775	}
2776	else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INSTANCED)
2777	{
2778		desc
2779			<< "drawArraysInstanced()\n"
2780			<< "\tfirst " << first << "\n"
2781			<< "\tinstance count " << instanceCount << "\n";
2782	}
2783	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS)
2784	{
2785		desc
2786			<< "drawElements()\n"
2787			<< "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2788			<< "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2789			<< "\tindex offset " << indexPointerOffset << "\n";
2790	}
2791	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED)
2792	{
2793		desc
2794			<< "drawElementsRanged()\n"
2795			<< "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2796			<< "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2797			<< "\tindex offset " << indexPointerOffset << "\n"
2798			<< "\trange start " << indexMin << "\n"
2799			<< "\trange end " << indexMax << "\n";
2800	}
2801	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED)
2802	{
2803		desc
2804			<< "drawElementsInstanced()\n"
2805			<< "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2806			<< "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2807			<< "\tindex offset " << indexPointerOffset << "\n"
2808			<< "\tinstance count " << instanceCount << "\n";
2809	}
2810	else if (drawMethod == DRAWMETHOD_DRAWARRAYS_INDIRECT)
2811	{
2812		desc
2813			<< "drawArraysIndirect()\n"
2814			<< "\tfirst " << first << "\n"
2815			<< "\tinstance count " << instanceCount << "\n"
2816			<< "\tindirect offset " << indirectOffset << "\n";
2817	}
2818	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT)
2819	{
2820		desc
2821			<< "drawElementsIndirect()\n"
2822			<< "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2823			<< "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2824			<< "\tindex offset " << indexPointerOffset << "\n"
2825			<< "\tinstance count " << instanceCount << "\n"
2826			<< "\tindirect offset " << indirectOffset << "\n"
2827			<< "\tbase vertex " << baseVertex << "\n";
2828	}
2829	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_BASEVERTEX)
2830	{
2831		desc
2832			<< "drawElementsBaseVertex()\n"
2833			<< "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2834			<< "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2835			<< "\tindex offset " << indexPointerOffset << "\n"
2836			<< "\tbase vertex " << baseVertex << "\n";
2837	}
2838	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INSTANCED_BASEVERTEX)
2839	{
2840		desc
2841			<< "drawElementsInstancedBaseVertex()\n"
2842			<< "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2843			<< "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2844			<< "\tindex offset " << indexPointerOffset << "\n"
2845			<< "\tinstance count " << instanceCount << "\n"
2846			<< "\tbase vertex " << baseVertex << "\n";
2847	}
2848	else if (drawMethod == DRAWMETHOD_DRAWELEMENTS_RANGED_BASEVERTEX)
2849	{
2850		desc
2851			<< "drawRangeElementsBaseVertex()\n"
2852			<< "\tindex type " << DrawTestSpec::indexTypeToString(indexType) << "\n"
2853			<< "\tindex storage in " << DrawTestSpec::storageToString(indexStorage) << "\n"
2854			<< "\tindex offset " << indexPointerOffset << "\n"
2855			<< "\tbase vertex " << baseVertex << "\n"
2856			<< "\trange start " << indexMin << "\n"
2857			<< "\trange end " << indexMax << "\n";
2858	}
2859	else
2860		DE_ASSERT(DE_FALSE);
2861
2862	desc << "\t" << primitiveCount << " ";
2863
2864	switch (primitive)
2865	{
2866		case DrawTestSpec::PRIMITIVE_POINTS:
2867			desc << "points";
2868			break;
2869		case DrawTestSpec::PRIMITIVE_TRIANGLES:
2870			desc << "triangles";
2871			break;
2872		case DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
2873			desc << "triangles (fan)";
2874			break;
2875		case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
2876			desc << "triangles (strip)";
2877			break;
2878		case DrawTestSpec::PRIMITIVE_LINES:
2879			desc << "lines";
2880			break;
2881		case DrawTestSpec::PRIMITIVE_LINE_STRIP:
2882			desc << "lines (strip)";
2883			break;
2884		case DrawTestSpec::PRIMITIVE_LINE_LOOP:
2885			desc << "lines (loop)";
2886			break;
2887		case DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
2888			desc << "lines (adjancency)";
2889			break;
2890		case DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
2891			desc << "lines (strip, adjancency)";
2892			break;
2893		case DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
2894			desc << "triangles (adjancency)";
2895			break;
2896		case DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
2897			desc << "triangles (strip, adjancency)";
2898			break;
2899		default:
2900			DE_ASSERT(false);
2901			break;
2902	}
2903
2904	desc << "\n";
2905
2906	return desc.str();
2907}
2908
2909DrawTestSpec::DrawTestSpec (void)
2910{
2911	primitive			= PRIMITIVE_LAST;
2912	primitiveCount		= 0;
2913	drawMethod			= DRAWMETHOD_LAST;
2914	indexType			= INDEXTYPE_LAST;
2915	indexPointerOffset	= 0;
2916	indexStorage		= STORAGE_LAST;
2917	first				= 0;
2918	indexMin			= 0;
2919	indexMax			= 0;
2920	instanceCount		= 0;
2921	indirectOffset		= 0;
2922	baseVertex			= 0;
2923}
2924
2925int DrawTestSpec::hash (void) const
2926{
2927	// Use only drawmode-relevant values in "hashing" as the unrelevant values might not be set (causing non-deterministic behavior).
2928	const MethodInfo	methodInfo		= getMethodInfo(drawMethod);
2929	const bool			arrayed			= methodInfo.first;
2930	const bool			instanced		= methodInfo.instanced;
2931	const bool			ranged			= methodInfo.ranged;
2932	const bool			indexed			= methodInfo.indexed;
2933	const bool			indirect		= methodInfo.indirect;
2934	const bool			hasBaseVtx		= methodInfo.baseVertex;
2935
2936	const int			indexHash		= (!indexed)	? (0) : (int(indexType) + 10 * indexPointerOffset + 100 * int(indexStorage));
2937	const int			arrayHash		= (!arrayed)	? (0) : (first);
2938	const int			indexRangeHash	= (!ranged)		? (0) : (indexMin + 10 * indexMax);
2939	const int			instanceHash	= (!instanced)	? (0) : (instanceCount);
2940	const int			indirectHash	= (!indirect)	? (0) : (indirectOffset);
2941	const int			baseVtxHash		= (!hasBaseVtx)	? (0) : (baseVertex);
2942	const int			basicHash		= int(primitive) + 10 * primitiveCount + 100 * int(drawMethod);
2943
2944	return indexHash + 3 * arrayHash + 5 * indexRangeHash + 7 * instanceHash + 13 * basicHash + 17 * (int)attribs.size() + 19 * primitiveCount + 23 * indirectHash + 27 * baseVtxHash;
2945}
2946
2947bool DrawTestSpec::valid (void) const
2948{
2949	DE_ASSERT(apiType.getProfile() != glu::PROFILE_LAST);
2950	DE_ASSERT(primitive != PRIMITIVE_LAST);
2951	DE_ASSERT(drawMethod != DRAWMETHOD_LAST);
2952
2953	const MethodInfo methodInfo = getMethodInfo(drawMethod);
2954
2955	for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
2956		if (!attribs[ndx].valid(apiType))
2957			return false;
2958
2959	if (methodInfo.ranged)
2960	{
2961		deUint32 maxIndexValue = 0;
2962		if (indexType == INDEXTYPE_BYTE)
2963			maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_BYTE).ub.getValue();
2964		else if (indexType == INDEXTYPE_SHORT)
2965			maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_SHORT).us.getValue();
2966		else if (indexType == INDEXTYPE_INT)
2967			maxIndexValue = GLValue::getMaxValue(INPUTTYPE_UNSIGNED_INT).ui.getValue();
2968		else
2969			DE_ASSERT(DE_FALSE);
2970
2971		if (indexMin > indexMax)
2972			return false;
2973		if (indexMin < 0 || indexMax < 0)
2974			return false;
2975		if ((deUint32)indexMin > maxIndexValue || (deUint32)indexMax > maxIndexValue)
2976			return false;
2977	}
2978
2979	if (methodInfo.first && first < 0)
2980		return false;
2981
2982	// GLES2 limits
2983	if (apiType == glu::ApiType::es(2,0))
2984	{
2985		if (drawMethod != gls::DrawTestSpec::DRAWMETHOD_DRAWARRAYS && drawMethod != gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS)
2986			return false;
2987		if (drawMethod == gls::DrawTestSpec::DRAWMETHOD_DRAWELEMENTS && (indexType != INDEXTYPE_BYTE && indexType != INDEXTYPE_SHORT))
2988			return false;
2989	}
2990
2991	// Indirect limitations
2992	if (methodInfo.indirect)
2993	{
2994		// Indirect offset alignment
2995		if (indirectOffset % 4 != 0)
2996			return false;
2997
2998		// All attribute arrays must be stored in a buffer
2999		for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
3000			if (!attribs[ndx].useDefaultAttribute && attribs[ndx].storage == gls::DrawTestSpec::STORAGE_USER)
3001				return false;
3002	}
3003	if (drawMethod == DRAWMETHOD_DRAWELEMENTS_INDIRECT)
3004	{
3005		// index offset must be convertable to firstIndex
3006		if (indexPointerOffset % gls::DrawTestSpec::indexTypeSize(indexType) != 0)
3007			return false;
3008
3009		// Indices must be in a buffer
3010		if (indexStorage != STORAGE_BUFFER)
3011			return false;
3012	}
3013
3014	// Do not allow user pointer in GL core
3015	if (apiType.getProfile() == glu::PROFILE_CORE)
3016	{
3017		if (methodInfo.indexed && indexStorage == DrawTestSpec::STORAGE_USER)
3018			return false;
3019	}
3020
3021	return true;
3022}
3023
3024DrawTestSpec::CompatibilityTestType DrawTestSpec::isCompatibilityTest (void) const
3025{
3026	const MethodInfo methodInfo = getMethodInfo(drawMethod);
3027
3028	bool bufferAlignmentBad = false;
3029	bool strideAlignmentBad = false;
3030
3031	// Attribute buffer alignment
3032	for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
3033		if (!attribs[ndx].isBufferAligned())
3034			bufferAlignmentBad = true;
3035
3036	// Attribute stride alignment
3037	for (int ndx = 0; ndx < (int)attribs.size(); ++ndx)
3038		if (!attribs[ndx].isBufferStrideAligned())
3039			strideAlignmentBad = true;
3040
3041	// Index buffer alignment
3042	if (methodInfo.indexed)
3043	{
3044		if (indexStorage == STORAGE_BUFFER)
3045		{
3046			int indexSize = 0;
3047			if (indexType == INDEXTYPE_BYTE)
3048				indexSize = 1;
3049			else if (indexType == INDEXTYPE_SHORT)
3050				indexSize = 2;
3051			else if (indexType == INDEXTYPE_INT)
3052				indexSize = 4;
3053			else
3054				DE_ASSERT(DE_FALSE);
3055
3056			if (indexPointerOffset % indexSize != 0)
3057				bufferAlignmentBad = true;
3058		}
3059	}
3060
3061	// \note combination bad alignment & stride is treated as bad offset
3062	if (bufferAlignmentBad)
3063		return COMPATIBILITY_UNALIGNED_OFFSET;
3064	else if (strideAlignmentBad)
3065		return COMPATIBILITY_UNALIGNED_STRIDE;
3066	else
3067		return COMPATIBILITY_NONE;
3068}
3069
3070// DrawTest
3071
3072DrawTest::DrawTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const DrawTestSpec& spec, const char* name, const char* desc)
3073	: TestCase			(testCtx, name, desc)
3074	, m_renderCtx		(renderCtx)
3075	, m_refBuffers		(DE_NULL)
3076	, m_refContext		(DE_NULL)
3077	, m_glesContext		(DE_NULL)
3078	, m_glArrayPack		(DE_NULL)
3079	, m_rrArrayPack		(DE_NULL)
3080	, m_maxDiffRed		(-1)
3081	, m_maxDiffGreen	(-1)
3082	, m_maxDiffBlue		(-1)
3083	, m_iteration		(0)
3084	, m_result			()	// \note no per-iteration result logging (only one iteration)
3085{
3086	addIteration(spec);
3087}
3088
3089DrawTest::DrawTest (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* desc)
3090	: TestCase			(testCtx, name, desc)
3091	, m_renderCtx		(renderCtx)
3092	, m_refBuffers		(DE_NULL)
3093	, m_refContext		(DE_NULL)
3094	, m_glesContext		(DE_NULL)
3095	, m_glArrayPack		(DE_NULL)
3096	, m_rrArrayPack		(DE_NULL)
3097	, m_maxDiffRed		(-1)
3098	, m_maxDiffGreen	(-1)
3099	, m_maxDiffBlue		(-1)
3100	, m_iteration		(0)
3101	, m_result			(testCtx.getLog(), "Iteration result: ")
3102{
3103}
3104
3105DrawTest::~DrawTest	(void)
3106{
3107	deinit();
3108}
3109
3110void DrawTest::addIteration (const DrawTestSpec& spec, const char* description)
3111{
3112	// Validate spec
3113	const bool validSpec = spec.valid();
3114	DE_ASSERT(validSpec);
3115
3116	if (!validSpec)
3117		return;
3118
3119	// Check the context type is the same with other iterations
3120	if (!m_specs.empty())
3121	{
3122		const bool validContext = m_specs[0].apiType == spec.apiType;
3123		DE_ASSERT(validContext);
3124
3125		if (!validContext)
3126			return;
3127	}
3128
3129	m_specs.push_back(spec);
3130
3131	if (description)
3132		m_iteration_descriptions.push_back(std::string(description));
3133	else
3134		m_iteration_descriptions.push_back(std::string());
3135}
3136
3137void DrawTest::init (void)
3138{
3139	const int						renderTargetWidth	= de::min(MAX_RENDER_TARGET_SIZE, m_renderCtx.getRenderTarget().getWidth());
3140	const int						renderTargetHeight	= de::min(MAX_RENDER_TARGET_SIZE, m_renderCtx.getRenderTarget().getHeight());
3141	sglr::ReferenceContextLimits	limits				(m_renderCtx);
3142	bool							useVao				= false;
3143
3144	m_glesContext = new sglr::GLContext(m_renderCtx, m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS | sglr::GLCONTEXT_LOG_PROGRAMS, tcu::IVec4(0, 0, renderTargetWidth, renderTargetHeight));
3145
3146	if (m_renderCtx.getType().getAPI() == glu::ApiType::es(2,0) || m_renderCtx.getType().getAPI() == glu::ApiType::es(3,0))
3147		useVao = false;
3148	else if (contextSupports(m_renderCtx.getType(), glu::ApiType::es(3,1)) || glu::isContextTypeGLCore(m_renderCtx.getType()))
3149		useVao = true;
3150	else
3151		DE_ASSERT(!"Unknown context type");
3152
3153	DE_ASSERT(!m_specs.empty());
3154	DE_ASSERT(contextSupports(m_renderCtx.getType(), m_specs[0].apiType));
3155
3156	m_refBuffers	= new sglr::ReferenceContextBuffers(m_renderCtx.getRenderTarget().getPixelFormat(), 0, 0, renderTargetWidth, renderTargetHeight);
3157	m_refContext	= new sglr::ReferenceContext(limits, m_refBuffers->getColorbuffer(), m_refBuffers->getDepthbuffer(), m_refBuffers->getStencilbuffer());
3158
3159	m_glArrayPack	= new AttributePack(m_testCtx, m_renderCtx, *m_glesContext, tcu::UVec2(renderTargetWidth, renderTargetHeight), useVao, true);
3160	m_rrArrayPack	= new AttributePack(m_testCtx, m_renderCtx, *m_refContext,  tcu::UVec2(renderTargetWidth, renderTargetHeight), useVao, false);
3161
3162	m_maxDiffRed	= deCeilFloatToInt32(256.0f * (6.0f / (1 << m_renderCtx.getRenderTarget().getPixelFormat().redBits)));
3163	m_maxDiffGreen	= deCeilFloatToInt32(256.0f * (6.0f / (1 << m_renderCtx.getRenderTarget().getPixelFormat().greenBits)));
3164	m_maxDiffBlue	= deCeilFloatToInt32(256.0f * (6.0f / (1 << m_renderCtx.getRenderTarget().getPixelFormat().blueBits)));
3165}
3166
3167void DrawTest::deinit (void)
3168{
3169	delete m_glArrayPack;
3170	delete m_rrArrayPack;
3171	delete m_refBuffers;
3172	delete m_refContext;
3173	delete m_glesContext;
3174
3175	m_glArrayPack	= DE_NULL;
3176	m_rrArrayPack	= DE_NULL;
3177	m_refBuffers	= DE_NULL;
3178	m_refContext	= DE_NULL;
3179	m_glesContext	= DE_NULL;
3180}
3181
3182DrawTest::IterateResult DrawTest::iterate (void)
3183{
3184	const int					specNdx			= (m_iteration / 2);
3185	const bool					drawStep		= (m_iteration % 2) == 0;
3186	const bool					compareStep		= (m_iteration % 2) == 1;
3187	const IterateResult			iterateResult	= ((size_t)m_iteration + 1 == m_specs.size()*2) ? (STOP) : (CONTINUE);
3188	const DrawTestSpec&			spec			= m_specs[specNdx];
3189	const bool					updateProgram	= (m_iteration == 0) || (drawStep && !checkSpecsShaderCompatible(m_specs[specNdx], m_specs[specNdx-1])); // try to use the same shader in all iterations
3190	IterationLogSectionEmitter	sectionEmitter	(m_testCtx.getLog(), specNdx, m_specs.size(), m_iteration_descriptions[specNdx], drawStep && m_specs.size()!=1);
3191
3192	if (drawStep)
3193	{
3194		const MethodInfo	methodInfo				= getMethodInfo(spec.drawMethod);
3195		const bool			indexed					= methodInfo.indexed;
3196		const bool			instanced				= methodInfo.instanced;
3197		const bool			ranged					= methodInfo.ranged;
3198		const bool			hasFirst				= methodInfo.first;
3199		const bool			hasBaseVtx				= methodInfo.baseVertex;
3200
3201		const size_t		primitiveElementCount	= getElementCount(spec.primitive, spec.primitiveCount);						// !< elements to be drawn
3202		const int			indexMin				= (ranged) ? (spec.indexMin) : (0);
3203		const int			firstAddition			= (hasFirst) ? (spec.first) : (0);
3204		const int			baseVertexAddition		= (hasBaseVtx && spec.baseVertex > 0) ? ( spec.baseVertex) : (0);			// spec.baseVertex > 0 => Create bigger attribute buffer
3205		const int			indexBase				= (hasBaseVtx && spec.baseVertex < 0) ? (-spec.baseVertex) : (0);			// spec.baseVertex < 0 => Create bigger indices
3206		const size_t		elementCount			= primitiveElementCount + indexMin + firstAddition + baseVertexAddition;	// !< elements in buffer (buffer should have at least primitiveElementCount ACCESSIBLE (index range, first) elements)
3207		const int			maxElementIndex			= (int)primitiveElementCount + indexMin + firstAddition - 1;
3208		const int			indexMax				= de::max(0, (ranged) ? (de::clamp<int>(spec.indexMax, 0, maxElementIndex)) : (maxElementIndex));
3209		float				coordScale				= getCoordScale(spec);
3210		float				colorScale				= getColorScale(spec);
3211
3212		rr::GenericVec4		nullAttribValue;
3213
3214		// Log info
3215		m_testCtx.getLog() << TestLog::Message << spec.getMultilineDesc() << TestLog::EndMessage;
3216		m_testCtx.getLog() << TestLog::Message << TestLog::EndMessage; // extra line for clarity
3217
3218		// Data
3219
3220		m_glArrayPack->clearArrays();
3221		m_rrArrayPack->clearArrays();
3222
3223		for (int attribNdx = 0; attribNdx < (int)spec.attribs.size(); attribNdx++)
3224		{
3225			DrawTestSpec::AttributeSpec attribSpec		= spec.attribs[attribNdx];
3226			const bool					isPositionAttr	= (attribNdx == 0) || (attribSpec.additionalPositionAttribute);
3227
3228			if (attribSpec.useDefaultAttribute)
3229			{
3230				const int		seed		= 10 * attribSpec.hash() + 100 * spec.hash() + attribNdx;
3231				rr::GenericVec4 attribValue = RandomArrayGenerator::generateAttributeValue(seed, attribSpec.inputType);
3232
3233				m_glArrayPack->newArray(DrawTestSpec::STORAGE_USER);
3234				m_rrArrayPack->newArray(DrawTestSpec::STORAGE_USER);
3235
3236				m_glArrayPack->getArray(attribNdx)->setupArray(false, 0, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, false, 0, 0, attribValue, isPositionAttr, false);
3237				m_rrArrayPack->getArray(attribNdx)->setupArray(false, 0, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, false, 0, 0, attribValue, isPositionAttr, false);
3238			}
3239			else
3240			{
3241				const int					seed					= attribSpec.hash() + 100 * spec.hash() + attribNdx;
3242				const size_t				elementSize				= attribSpec.componentCount * DrawTestSpec::inputTypeSize(attribSpec.inputType);
3243				const size_t				stride					= (attribSpec.stride == 0) ? (elementSize) : (attribSpec.stride);
3244				const size_t				evaluatedElementCount	= (instanced && attribSpec.instanceDivisor > 0) ? (spec.instanceCount / attribSpec.instanceDivisor + 1) : (elementCount);
3245				const size_t				referencedElementCount	= (ranged) ? (de::max<size_t>(evaluatedElementCount, spec.indexMax + 1)) : (evaluatedElementCount);
3246				const size_t				bufferSize				= attribSpec.offset + stride * (referencedElementCount - 1) + elementSize;
3247				const char*					data					= RandomArrayGenerator::generateArray(seed, (int)referencedElementCount, attribSpec.componentCount, attribSpec.offset, (int)stride, attribSpec.inputType);
3248
3249				try
3250				{
3251					m_glArrayPack->newArray(attribSpec.storage);
3252					m_rrArrayPack->newArray(attribSpec.storage);
3253
3254					m_glArrayPack->getArray(attribNdx)->data(DrawTestSpec::TARGET_ARRAY, bufferSize, data, attribSpec.usage);
3255					m_rrArrayPack->getArray(attribNdx)->data(DrawTestSpec::TARGET_ARRAY, bufferSize, data, attribSpec.usage);
3256
3257					m_glArrayPack->getArray(attribNdx)->setupArray(true, attribSpec.offset, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, attribSpec.normalize, attribSpec.stride, attribSpec.instanceDivisor, nullAttribValue, isPositionAttr, attribSpec.bgraComponentOrder);
3258					m_rrArrayPack->getArray(attribNdx)->setupArray(true, attribSpec.offset, attribSpec.componentCount, attribSpec.inputType, attribSpec.outputType, attribSpec.normalize, attribSpec.stride, attribSpec.instanceDivisor, nullAttribValue, isPositionAttr, attribSpec.bgraComponentOrder);
3259
3260					delete [] data;
3261					data = NULL;
3262				}
3263				catch (...)
3264				{
3265					delete [] data;
3266					throw;
3267				}
3268			}
3269		}
3270
3271		// Shader program
3272		if (updateProgram)
3273		{
3274			m_glArrayPack->updateProgram();
3275			m_rrArrayPack->updateProgram();
3276		}
3277
3278		// Draw
3279		try
3280		{
3281			// indices
3282			if (indexed)
3283			{
3284				const int		seed				= spec.hash();
3285				const size_t	indexElementSize	= DrawTestSpec::indexTypeSize(spec.indexType);
3286				const size_t	indexArraySize		= spec.indexPointerOffset + indexElementSize * elementCount;
3287				const char*		indexArray			= RandomArrayGenerator::generateIndices(seed, (int)elementCount, spec.indexType, spec.indexPointerOffset, indexMin, indexMax, indexBase);
3288				const char*		indexPointerBase	= (spec.indexStorage == DrawTestSpec::STORAGE_USER) ? (indexArray) : ((char*)DE_NULL);
3289				const char*		indexPointer		= indexPointerBase + spec.indexPointerOffset;
3290
3291				de::UniquePtr<AttributeArray> glArray	(new AttributeArray(spec.indexStorage, *m_glesContext));
3292				de::UniquePtr<AttributeArray> rrArray	(new AttributeArray(spec.indexStorage, *m_refContext));
3293
3294				try
3295				{
3296					glArray->data(DrawTestSpec::TARGET_ELEMENT_ARRAY, indexArraySize, indexArray, DrawTestSpec::USAGE_STATIC_DRAW);
3297					rrArray->data(DrawTestSpec::TARGET_ELEMENT_ARRAY, indexArraySize, indexArray, DrawTestSpec::USAGE_STATIC_DRAW);
3298
3299					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());
3300					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());
3301
3302					delete [] indexArray;
3303					indexArray = NULL;
3304				}
3305				catch (...)
3306				{
3307					delete [] indexArray;
3308					throw;
3309				}
3310			}
3311			else
3312			{
3313				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);
3314				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);
3315			}
3316		}
3317		catch (glu::Error& err)
3318		{
3319			// GL Errors are ok if the mode is not properly aligned
3320
3321			const DrawTestSpec::CompatibilityTestType ctype = spec.isCompatibilityTest();
3322
3323			m_testCtx.getLog() << TestLog::Message << "Got error: " << err.what() << TestLog::EndMessage;
3324
3325			if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET)
3326				m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
3327			else if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
3328				m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
3329			else
3330				throw;
3331		}
3332	}
3333	else if (compareStep)
3334	{
3335		if (!compare(spec.primitive))
3336		{
3337			const DrawTestSpec::CompatibilityTestType ctype = spec.isCompatibilityTest();
3338
3339			if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_OFFSET)
3340				m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned buffers.");
3341			else if (ctype == DrawTestSpec::COMPATIBILITY_UNALIGNED_STRIDE)
3342				m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Failed to draw with unaligned stride.");
3343			else
3344				m_result.addResult(QP_TEST_RESULT_FAIL, "Image comparison failed.");
3345		}
3346	}
3347	else
3348	{
3349		DE_ASSERT(false);
3350		return STOP;
3351	}
3352
3353	m_result.setTestContextResult(m_testCtx);
3354
3355	m_iteration++;
3356	return iterateResult;
3357}
3358
3359enum PrimitiveClass
3360{
3361	PRIMITIVECLASS_POINT = 0,
3362	PRIMITIVECLASS_LINE,
3363	PRIMITIVECLASS_TRIANGLE,
3364
3365	PRIMITIVECLASS_LAST
3366};
3367
3368static PrimitiveClass getDrawPrimitiveClass (gls::DrawTestSpec::Primitive primitiveType)
3369{
3370	switch (primitiveType)
3371	{
3372		case gls::DrawTestSpec::PRIMITIVE_POINTS:
3373			return PRIMITIVECLASS_POINT;
3374
3375		case gls::DrawTestSpec::PRIMITIVE_LINES:
3376		case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP:
3377		case gls::DrawTestSpec::PRIMITIVE_LINE_LOOP:
3378		case gls::DrawTestSpec::PRIMITIVE_LINES_ADJACENCY:
3379		case gls::DrawTestSpec::PRIMITIVE_LINE_STRIP_ADJACENCY:
3380			return PRIMITIVECLASS_LINE;
3381
3382		case gls::DrawTestSpec::PRIMITIVE_TRIANGLES:
3383		case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_FAN:
3384		case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP:
3385		case gls::DrawTestSpec::PRIMITIVE_TRIANGLES_ADJACENCY:
3386		case gls::DrawTestSpec::PRIMITIVE_TRIANGLE_STRIP_ADJACENCY:
3387			return PRIMITIVECLASS_TRIANGLE;
3388
3389		default:
3390			DE_ASSERT(false);
3391			return PRIMITIVECLASS_LAST;
3392	}
3393}
3394
3395static bool isBlack (const tcu::RGBA& c)
3396{
3397	// ignore alpha channel
3398	return c.getRed() == 0 && c.getGreen() == 0 && c.getBlue() == 0;
3399}
3400
3401static bool isEdgeTripletComponent (int c1, int c2, int c3, int renderTargetDifference)
3402{
3403	const int	roundingDifference	= 2 * renderTargetDifference; // src and dst pixels rounded to different directions
3404	const int	d1					= c2 - c1;
3405	const int	d2					= c3 - c2;
3406	const int	rampDiff			= de::abs(d2 - d1);
3407
3408	return rampDiff > roundingDifference;
3409}
3410
3411static bool isEdgeTriplet (const tcu::RGBA& c1, const tcu::RGBA& c2, const tcu::RGBA& c3, const tcu::IVec3& renderTargetThreshold)
3412{
3413	// black (background color) and non-black is always an edge
3414	{
3415		const bool b1 = isBlack(c1);
3416		const bool b2 = isBlack(c2);
3417		const bool b3 = isBlack(c3);
3418
3419		// both pixels with coverage and pixels without coverage
3420		if ((b1 && b2 && b3) == false && (b1 || b2 || b3) == true)
3421			return true;
3422		// all black
3423		if (b1 && b2 && b3)
3424			return false;
3425		// all with coverage
3426		DE_ASSERT(!b1 && !b2 && !b3);
3427	}
3428
3429	// Color is always linearly interpolated => component values change nearly linearly
3430	// in any constant direction on triangle hull. (df/dx ~= C).
3431
3432	// Edge detection (this function) is run against the reference image
3433	// => no dithering to worry about
3434
3435	return	isEdgeTripletComponent(c1.getRed(),		c2.getRed(),	c3.getRed(),	renderTargetThreshold.x())	||
3436			isEdgeTripletComponent(c1.getGreen(),	c2.getGreen(),	c3.getGreen(),	renderTargetThreshold.y())	||
3437			isEdgeTripletComponent(c1.getBlue(),	c2.getBlue(),	c3.getBlue(),	renderTargetThreshold.z());
3438}
3439
3440static bool pixelNearEdge (int x, int y, const tcu::Surface& ref, const tcu::IVec3& renderTargetThreshold)
3441{
3442	// should not be called for edge pixels
3443	DE_ASSERT(x >= 1 && x <= ref.getWidth()-2);
3444	DE_ASSERT(y >= 1 && y <= ref.getHeight()-2);
3445
3446	// horizontal
3447
3448	for (int dy = -1; dy < 2; ++dy)
3449	{
3450		const tcu::RGBA c1 = ref.getPixel(x-1, y+dy);
3451		const tcu::RGBA c2 = ref.getPixel(x,   y+dy);
3452		const tcu::RGBA c3 = ref.getPixel(x+1, y+dy);
3453		if (isEdgeTriplet(c1, c2, c3, renderTargetThreshold))
3454			return true;
3455	}
3456
3457	// vertical
3458
3459	for (int dx = -1; dx < 2; ++dx)
3460	{
3461		const tcu::RGBA c1 = ref.getPixel(x+dx, y-1);
3462		const tcu::RGBA c2 = ref.getPixel(x+dx, y);
3463		const tcu::RGBA c3 = ref.getPixel(x+dx, y+1);
3464		if (isEdgeTriplet(c1, c2, c3, renderTargetThreshold))
3465			return true;
3466	}
3467
3468	return false;
3469}
3470
3471static deUint32 getVisualizationGrayscaleColor (const tcu::RGBA& c)
3472{
3473	// make triangle coverage and error pixels obvious by converting coverage to grayscale
3474	if (isBlack(c))
3475		return 0;
3476	else
3477		return 50u + (deUint32)(c.getRed() + c.getBlue() + c.getGreen()) / 8u;
3478}
3479
3480static bool pixelNearLineIntersection (int x, int y, const tcu::Surface& target)
3481{
3482	// should not be called for edge pixels
3483	DE_ASSERT(x >= 1 && x <= target.getWidth()-2);
3484	DE_ASSERT(y >= 1 && y <= target.getHeight()-2);
3485
3486	int coveredPixels = 0;
3487
3488	for (int dy = -1; dy < 2; dy++)
3489	for (int dx = -1; dx < 2; dx++)
3490	{
3491		const bool targetCoverage = !isBlack(target.getPixel(x+dx, y+dy));
3492		if (targetCoverage)
3493		{
3494			++coveredPixels;
3495
3496			// A single thin line cannot have more than 3 covered pixels in a 3x3 area
3497			if (coveredPixels >= 4)
3498				return true;
3499		}
3500	}
3501
3502	return false;
3503}
3504
3505static inline bool colorsEqual (const tcu::RGBA& colorA, const tcu::RGBA& colorB, const tcu::IVec3& compareThreshold)
3506{
3507	enum
3508	{
3509		TCU_RGBA_RGB_MASK = tcu::RGBA::RED_MASK | tcu::RGBA::GREEN_MASK | tcu::RGBA::BLUE_MASK
3510	};
3511
3512	return tcu::compareThresholdMasked(colorA, colorB, tcu::RGBA(compareThreshold.x(), compareThreshold.y(), compareThreshold.z(), 0), TCU_RGBA_RGB_MASK);
3513}
3514
3515// search 3x3 are for matching color
3516static bool pixelNeighborhoodContainsColor (const tcu::Surface& target, int x, int y, const tcu::RGBA& color, const tcu::IVec3& compareThreshold)
3517{
3518	// should not be called for edge pixels
3519	DE_ASSERT(x >= 1 && x <= target.getWidth()-2);
3520	DE_ASSERT(y >= 1 && y <= target.getHeight()-2);
3521
3522	for (int dy = -1; dy < 2; dy++)
3523	for (int dx = -1; dx < 2; dx++)
3524	{
3525		const tcu::RGBA	targetCmpPixel = target.getPixel(x+dx, y+dy);
3526		if (colorsEqual(color, targetCmpPixel, compareThreshold))
3527			return true;
3528	}
3529
3530	return false;
3531}
3532
3533// search 3x3 are for matching coverage (coverage == (color != background color))
3534static bool pixelNeighborhoodContainsCoverage (const tcu::Surface& target, int x, int y, bool coverage)
3535{
3536	// should not be called for edge pixels
3537	DE_ASSERT(x >= 1 && x <= target.getWidth()-2);
3538	DE_ASSERT(y >= 1 && y <= target.getHeight()-2);
3539
3540	for (int dy = -1; dy < 2; dy++)
3541	for (int dx = -1; dx < 2; dx++)
3542	{
3543		const bool targetCmpCoverage = !isBlack(target.getPixel(x+dx, y+dy));
3544		if (targetCmpCoverage == coverage)
3545			return true;
3546	}
3547
3548	return false;
3549}
3550
3551static 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)
3552{
3553	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3554
3555	const tcu::IVec4				green						(0, 255, 0, 255);
3556	const tcu::IVec4				red							(255, 0, 0, 255);
3557	const int						width						= reference.getWidth();
3558	const int						height						= reference.getHeight();
3559	tcu::TextureLevel				errorMask					(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), width, height);
3560	const tcu::PixelBufferAccess	errorAccess					= errorMask.getAccess();
3561	int								numFailingPixels			= 0;
3562
3563	// clear errormask edges which would otherwise be transparent
3564
3565	tcu::clear(tcu::getSubregion(errorAccess, 0,			0,			width,	1),			green);
3566	tcu::clear(tcu::getSubregion(errorAccess, 0,			height-1,	width,	1),			green);
3567	tcu::clear(tcu::getSubregion(errorAccess, 0,			0,			1,		height),	green);
3568	tcu::clear(tcu::getSubregion(errorAccess, width-1,		0,			1,		height),	green);
3569
3570	// skip edge pixels since coverage on edge cannot be verified
3571
3572	for (int y = 1; y < height - 1; ++y)
3573	for (int x = 1; x < width - 1; ++x)
3574	{
3575		const tcu::RGBA	refPixel			= reference.getPixel(x, y);
3576		const tcu::RGBA	screenPixel			= result.getPixel(x, y);
3577		const bool		directMatch			= colorsEqual(refPixel, screenPixel, compareThreshold);
3578		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.)
3579		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.)
3580
3581		if (isOkScreenPixel && isOkReferencePixel)
3582		{
3583			// pixel valid, write greenish pixels to make the result image easier to read
3584			const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
3585			errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
3586		}
3587		else if (!pixelNearEdge(x, y, reference, renderTargetThreshold))
3588		{
3589			// non-edge pixel values must be within threshold of the reference values
3590			errorAccess.setPixel(red, x, y);
3591			++numFailingPixels;
3592		}
3593		else
3594		{
3595			// we are on/near an edge, verify only coverage (coverage == not background colored)
3596			const bool	referenceCoverage		= !isBlack(refPixel);
3597			const bool	screenCoverage			= !isBlack(screenPixel);
3598			const bool	isOkReferenceCoverage	= pixelNeighborhoodContainsCoverage(result, x, y, referenceCoverage);	// Check reference pixel against screen pixel
3599			const bool	isOkScreenCoverage		= pixelNeighborhoodContainsCoverage(reference, x, y, screenCoverage);	// Check screen pixels against reference pixel
3600
3601			if (isOkScreenCoverage && isOkReferenceCoverage)
3602			{
3603				// pixel valid, write greenish pixels to make the result image easier to read
3604				const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
3605				errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
3606			}
3607			else
3608			{
3609				// coverage does not match
3610				errorAccess.setPixel(red, x, y);
3611				++numFailingPixels;
3612			}
3613		}
3614	}
3615
3616	log	<< TestLog::Message
3617		<< "Comparing images:\n"
3618		<< "\tallowed deviation in pixel positions = 1\n"
3619		<< "\tnumber of allowed invalid pixels = " << maxAllowedInvalidPixels << "\n"
3620		<< "\tnumber of invalid pixels = " << numFailingPixels
3621		<< TestLog::EndMessage;
3622
3623	if (numFailingPixels > maxAllowedInvalidPixels)
3624	{
3625		log << TestLog::Message
3626			<< "Image comparison failed. Color threshold = (" << compareThreshold.x() << ", " << compareThreshold.y() << ", " << compareThreshold.z() << ")"
3627			<< TestLog::EndMessage
3628			<< TestLog::ImageSet(imageSetName, imageSetDesc)
3629			<< TestLog::Image("Result",		"Result",		result)
3630			<< TestLog::Image("Reference",	"Reference",	reference)
3631			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
3632			<< TestLog::EndImageSet;
3633
3634		return false;
3635	}
3636	else
3637	{
3638		log << TestLog::ImageSet(imageSetName, imageSetDesc)
3639			<< TestLog::Image("Result", "Result", result)
3640			<< TestLog::EndImageSet;
3641
3642		return true;
3643	}
3644}
3645
3646static 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)
3647{
3648	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
3649
3650	const tcu::IVec4				green						(0, 255, 0, 255);
3651	const tcu::IVec4				red							(255, 0, 0, 255);
3652	const int						width						= reference.getWidth();
3653	const int						height						= reference.getHeight();
3654	tcu::TextureLevel				errorMask					(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), width, height);
3655	const tcu::PixelBufferAccess	errorAccess					= errorMask.getAccess();
3656	int								numFailingPixels			= 0;
3657
3658	// clear errormask edges which would otherwise be transparent
3659
3660	tcu::clear(tcu::getSubregion(errorAccess, 0,			0,			width,	1),			green);
3661	tcu::clear(tcu::getSubregion(errorAccess, 0,			height-1,	width,	1),			green);
3662	tcu::clear(tcu::getSubregion(errorAccess, 0,			0,			1,		height),	green);
3663	tcu::clear(tcu::getSubregion(errorAccess, width-1,		0,			1,		height),	green);
3664
3665	// skip edge pixels since coverage on edge cannot be verified
3666
3667	for (int y = 1; y < height - 1; ++y)
3668	for (int x = 1; x < width - 1; ++x)
3669	{
3670		const tcu::RGBA	refPixel			= reference.getPixel(x, y);
3671		const tcu::RGBA	screenPixel			= result.getPixel(x, y);
3672		const bool		directMatch			= colorsEqual(refPixel, screenPixel, compareThreshold);
3673		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.)
3674		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.)
3675
3676		if (isOkScreenPixel && isOkReferencePixel)
3677		{
3678			// pixel valid, write greenish pixels to make the result image easier to read
3679			const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
3680			errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
3681		}
3682		else if (!pixelNearLineIntersection(x, y, reference) &&
3683				 !pixelNearLineIntersection(x, y, result))
3684		{
3685			// non-intersection pixel values must be within threshold of the reference values
3686			errorAccess.setPixel(red, x, y);
3687			++numFailingPixels;
3688		}
3689		else
3690		{
3691			// pixel is near a line intersection
3692			// we are on/near an edge, verify only coverage (coverage == not background colored)
3693			const bool	referenceCoverage		= !isBlack(refPixel);
3694			const bool	screenCoverage			= !isBlack(screenPixel);
3695			const bool	isOkScreenCoverage		= pixelNeighborhoodContainsCoverage(reference, x, y, screenCoverage);	// Check screen pixels against reference pixel
3696			const bool	isOkReferenceCoverage	= pixelNeighborhoodContainsCoverage(result, x, y, referenceCoverage);	// Check reference pixel against screen pixel
3697
3698			if (isOkScreenCoverage && isOkReferenceCoverage)
3699			{
3700				// pixel valid, write greenish pixels to make the result image easier to read
3701				const deUint32 grayscaleValue = getVisualizationGrayscaleColor(screenPixel);
3702				errorAccess.setPixel(tcu::UVec4(grayscaleValue, 255, grayscaleValue, 255), x, y);
3703			}
3704			else
3705			{
3706				// coverage does not match
3707				errorAccess.setPixel(red, x, y);
3708				++numFailingPixels;
3709			}
3710		}
3711	}
3712
3713	log	<< TestLog::Message
3714		<< "Comparing images:\n"
3715		<< "\tallowed deviation in pixel positions = 1\n"
3716		<< "\tnumber of allowed invalid pixels = " << maxAllowedInvalidPixels << "\n"
3717		<< "\tnumber of invalid pixels = " << numFailingPixels
3718		<< TestLog::EndMessage;
3719
3720	if (numFailingPixels > maxAllowedInvalidPixels)
3721	{
3722		log << TestLog::Message
3723			<< "Image comparison failed. Color threshold = (" << compareThreshold.x() << ", " << compareThreshold.y() << ", " << compareThreshold.z() << ")"
3724			<< TestLog::EndMessage
3725			<< TestLog::ImageSet(imageSetName, imageSetDesc)
3726			<< TestLog::Image("Result",		"Result",		result)
3727			<< TestLog::Image("Reference",	"Reference",	reference)
3728			<< TestLog::Image("ErrorMask",	"Error mask",	errorMask)
3729			<< TestLog::EndImageSet;
3730
3731		return false;
3732	}
3733	else
3734	{
3735		log << TestLog::ImageSet(imageSetName, imageSetDesc)
3736			<< TestLog::Image("Result", "Result", result)
3737			<< TestLog::EndImageSet;
3738
3739		return true;
3740	}
3741}
3742
3743bool DrawTest::compare (gls::DrawTestSpec::Primitive primitiveType)
3744{
3745	const tcu::Surface&	ref		= m_rrArrayPack->getSurface();
3746	const tcu::Surface&	screen	= m_glArrayPack->getSurface();
3747
3748	if (m_renderCtx.getRenderTarget().getNumSamples() > 1)
3749	{
3750		// \todo [mika] Improve compare when using multisampling
3751		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;
3752		return tcu::fuzzyCompare(m_testCtx.getLog(), "Compare Results", "Compare Results", ref.getAccess(), screen.getAccess(), 0.3f, tcu::COMPARE_LOG_RESULT);
3753	}
3754	else
3755	{
3756		const PrimitiveClass primitiveClass = getDrawPrimitiveClass(primitiveType);
3757
3758		switch (primitiveClass)
3759		{
3760			case PRIMITIVECLASS_POINT:
3761			{
3762				// Point are extremely unlikely to have overlapping regions, don't allow any no extra / missing pixels
3763				const int maxAllowedInvalidPixelsWithPoints = 0;
3764				return tcu::intThresholdPositionDeviationErrorThresholdCompare(m_testCtx.getLog(),
3765																			   "CompareResult",
3766																			   "Result of rendering",
3767																			   ref.getAccess(),
3768																			   screen.getAccess(),
3769																			   tcu::UVec4(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue, 256),
3770																			   tcu::IVec3(1, 1, 0),					//!< 3x3 search kernel
3771																			   true,								//!< relax comparison on the image boundary
3772																			   maxAllowedInvalidPixelsWithPoints,	//!< error threshold
3773																			   tcu::COMPARE_LOG_RESULT);
3774			}
3775
3776			case PRIMITIVECLASS_LINE:
3777			{
3778				// Lines can potentially have a large number of overlapping pixels. Pixel comparison may potentially produce
3779				// false negatives in such pixels if for example the pixel in question is overdrawn by another line in the
3780				// reference image but not in the resultin image. Relax comparison near line intersection points (areas) and
3781				// compare only coverage, not color, in such pixels
3782				const int maxAllowedInvalidPixelsWithLines = 5; // line are allowed to have a few bad pixels
3783				return intersectionRelaxedLineImageCompare(m_testCtx.getLog(),
3784														   "CompareResult",
3785														   "Result of rendering",
3786														   ref,
3787														   screen,
3788														   tcu::IVec3(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue),
3789														   maxAllowedInvalidPixelsWithLines);
3790			}
3791
3792			case PRIMITIVECLASS_TRIANGLE:
3793			{
3794				// Triangles are likely to partially or fully overlap. Pixel difference comparison is fragile in pixels
3795				// where there could be potential overlapping since the  pixels might be covered by one triangle in the
3796				// reference image and by the other in the result image. Relax comparsion near primitive edges and
3797				// compare only coverage, not color, in such pixels.
3798				const int			maxAllowedInvalidPixelsWithTriangles	= 10;
3799				const tcu::IVec3	renderTargetThreshold					= m_renderCtx.getRenderTarget().getPixelFormat().getColorThreshold().toIVec().xyz();
3800
3801				return edgeRelaxedImageCompare(m_testCtx.getLog(),
3802											   "CompareResult",
3803											   "Result of rendering",
3804											   ref,
3805											   screen,
3806											   tcu::IVec3(m_maxDiffRed, m_maxDiffGreen, m_maxDiffBlue),
3807											   renderTargetThreshold,
3808											   maxAllowedInvalidPixelsWithTriangles);
3809			}
3810
3811			default:
3812				DE_ASSERT(false);
3813				return false;
3814		}
3815	}
3816}
3817
3818float DrawTest::getCoordScale (const DrawTestSpec& spec) const
3819{
3820	float maxValue = 1.0f;
3821
3822	for (int arrayNdx = 0; arrayNdx < (int)spec.attribs.size(); arrayNdx++)
3823	{
3824		DrawTestSpec::AttributeSpec attribSpec		= spec.attribs[arrayNdx];
3825		const bool					isPositionAttr	= (arrayNdx == 0) || (attribSpec.additionalPositionAttribute);
3826		float						attrMaxValue	= 0;
3827
3828		if (!isPositionAttr)
3829			continue;
3830
3831		if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
3832		{
3833			if (attribSpec.normalize)
3834				attrMaxValue += 1.0f;
3835			else
3836				attrMaxValue += 1024.0;
3837		}
3838		else if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10)
3839		{
3840			if (attribSpec.normalize)
3841				attrMaxValue += 1.0f;
3842			else
3843				attrMaxValue += 512.0;
3844		}
3845		else
3846		{
3847			const float max = GLValue::getMaxValue(attribSpec.inputType).toFloat();
3848
3849			attrMaxValue += (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType)) ? (1.0f) : (max * 1.1f);
3850		}
3851
3852		if (attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC4
3853			|| attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC4
3854			|| attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC3 || attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC4)
3855				attrMaxValue *= 2;
3856
3857		maxValue += attrMaxValue;
3858	}
3859
3860	return 1.0f / maxValue;
3861}
3862
3863float DrawTest::getColorScale (const DrawTestSpec& spec) const
3864{
3865	float colorScale = 1.0f;
3866
3867	for (int arrayNdx = 1; arrayNdx < (int)spec.attribs.size(); arrayNdx++)
3868	{
3869		DrawTestSpec::AttributeSpec attribSpec		= spec.attribs[arrayNdx];
3870		const bool					isPositionAttr	= (arrayNdx == 0) || (attribSpec.additionalPositionAttribute);
3871
3872		if (isPositionAttr)
3873			continue;
3874
3875		if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_UNSIGNED_INT_2_10_10_10)
3876		{
3877			if (!attribSpec.normalize)
3878				colorScale *= 1.0 / 1024.0;
3879		}
3880		else if (attribSpec.inputType == DrawTestSpec::INPUTTYPE_INT_2_10_10_10)
3881		{
3882			if (!attribSpec.normalize)
3883				colorScale *= 1.0 / 512.0;
3884		}
3885		else
3886		{
3887			const float max = GLValue::getMaxValue(attribSpec.inputType).toFloat();
3888
3889			colorScale *= (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType) ? 1.0f : float(1.0 / double(max)));
3890			if (attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_VEC4 ||
3891				attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_UVEC4 ||
3892				attribSpec.outputType == DrawTestSpec::OUTPUTTYPE_IVEC4)
3893				colorScale *= (attribSpec.normalize && !inputTypeIsFloatType(attribSpec.inputType) ? 1.0f : float(1.0 / double(max)));
3894		}
3895	}
3896
3897	return colorScale;
3898}
3899
3900} // gls
3901} // deqp
3902