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