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