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