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