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