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