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