1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 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 Default vertex attribute test
22 *//*--------------------------------------------------------------------*/
23
24#include "es3fDefaultVertexAttributeTests.hpp"
25#include "tcuVector.hpp"
26#include "tcuRenderTarget.hpp"
27#include "tcuSurface.hpp"
28#include "tcuTextureUtil.hpp"
29#include "gluRenderContext.hpp"
30#include "gluCallLogWrapper.hpp"
31#include "gluShaderProgram.hpp"
32#include "gluObjectWrapper.hpp"
33#include "gluPixelTransfer.hpp"
34#include "glwEnums.hpp"
35#include "glwFunctions.hpp"
36#include "deMath.h"
37#include "deStringUtil.hpp"
38#include "deString.h"
39
40#include <limits>
41
42namespace deqp
43{
44namespace gles3
45{
46namespace Functional
47{
48namespace
49{
50
51static const int s_valueRange = 10;
52
53static const char* const s_passThroughFragmentShaderSource =	"#version 300 es\n"
54																"layout(location = 0) out mediump vec4 fragColor;\n"
55																"in mediump vec4 v_color;\n"
56																"void main (void)\n"
57																"{\n"
58																"	fragColor = v_color;\n"
59																"}\n";
60
61template <typename T1, int S1, typename T2, int S2>
62tcu::Vector<T1, S1> convertToTypeVec (const tcu::Vector<T2, S2>& v)
63{
64	tcu::Vector<T1, S1> retVal;
65
66	for (int ndx = 0; ndx < S1; ++ndx)
67		retVal[ndx] = T1(0);
68
69	if (S1 == 4)
70		retVal[3] = T1(1);
71
72	for (int ndx = 0; ndx < de::min(S1, S2); ++ndx)
73		retVal[ndx] = T1(v[ndx]);
74
75	return retVal;
76}
77
78class FloatLoader
79{
80public:
81	virtual				~FloatLoader	(void) {};
82
83	// returns the value loaded
84	virtual tcu::Vec4	load			(glu::CallLogWrapper& gl, int index, const tcu::Vec4& v) const = 0;
85};
86
87#define GEN_DIRECT_FLOAT_LOADER(TYPE, COMPS, TYPECODE, CASENAME, VALUES)				\
88	class LoaderVertexAttrib##COMPS##TYPECODE : public FloatLoader						\
89	{																					\
90	public:																				\
91		enum																			\
92		{																				\
93			NORMALIZING = 0,															\
94		};																				\
95		enum																			\
96		{																				\
97			COMPONENTS = COMPS															\
98		};																				\
99		typedef TYPE Type;																\
100																						\
101		tcu::Vec4 load (glu::CallLogWrapper& gl, int index, const tcu::Vec4& v) const	\
102		{																				\
103			tcu::Vector<TYPE, COMPONENTS> value;										\
104			value = convertToTypeVec<Type, COMPONENTS>(v);								\
105																						\
106			gl.glVertexAttrib ##COMPS ##TYPECODE VALUES;								\
107			return convertToTypeVec<float, 4>(value);									\
108		}																				\
109																						\
110		static const char* getCaseName (void)											\
111		{																				\
112			return CASENAME;															\
113		}																				\
114																						\
115		static const char* getName (void)												\
116		{																				\
117			return "VertexAttrib" #COMPS #TYPECODE;										\
118		}																				\
119	}
120
121#define GEN_INDIRECT_FLOAT_LOADER(TYPE, COMPS, TYPECODE, CASENAME)						\
122	class LoaderVertexAttrib##COMPS##TYPECODE : public FloatLoader						\
123	{																					\
124	public:																				\
125		enum																			\
126		{																				\
127			NORMALIZING = 0,															\
128		};																				\
129		enum																			\
130		{																				\
131			COMPONENTS = COMPS															\
132		};																				\
133		typedef TYPE Type;																\
134																						\
135		tcu::Vec4 load (glu::CallLogWrapper& gl, int index, const tcu::Vec4& v) const	\
136		{																				\
137			tcu::Vector<TYPE, COMPONENTS> value;										\
138			value = convertToTypeVec<Type, COMPONENTS>(v);								\
139																						\
140			gl.glVertexAttrib ##COMPS ##TYPECODE (index, value.getPtr());				\
141			return convertToTypeVec<float, 4>(value);									\
142		}																				\
143																						\
144		static const char* getCaseName (void)											\
145		{																				\
146			return CASENAME;															\
147		}																				\
148																						\
149		static const char* getName (void)												\
150		{																				\
151			return "VertexAttrib" #COMPS #TYPECODE;										\
152		}																				\
153	}
154
155#define GEN_DIRECT_INTEGER_LOADER(TYPE, COMPS, TYPECODE, CASENAME, VALUES)				\
156	class LoaderVertexAttribI##COMPS##TYPECODE : public FloatLoader						\
157	{																					\
158	public:																				\
159		enum																			\
160		{																				\
161			NORMALIZING = 0,															\
162		};																				\
163		enum																			\
164		{																				\
165			COMPONENTS = COMPS															\
166		};																				\
167		typedef TYPE Type;																\
168																						\
169		tcu::Vec4 load (glu::CallLogWrapper& gl, int index, const tcu::Vec4& v) const	\
170		{																				\
171			tcu::Vector<TYPE, COMPONENTS> value;										\
172			value = convertToTypeVec<Type, COMPONENTS>(v);								\
173																						\
174			gl.glVertexAttribI ##COMPS ##TYPECODE VALUES;								\
175			return convertToTypeVec<float, 4>(value);									\
176		}																				\
177																						\
178		static const char* getCaseName (void)											\
179		{																				\
180			return CASENAME;															\
181		}																				\
182																						\
183		static const char* getName (void)												\
184		{																				\
185			return "VertexAttrib" #COMPS #TYPECODE;										\
186		}																				\
187	}
188
189#define GEN_INDIRECT_INTEGER_LOADER(TYPE, COMPS, TYPECODE, CASENAME)					\
190	class LoaderVertexAttribI##COMPS##TYPECODE : public FloatLoader						\
191	{																					\
192	public:																				\
193		enum																			\
194		{																				\
195			NORMALIZING = 0,															\
196		};																				\
197		enum																			\
198		{																				\
199			COMPONENTS = COMPS															\
200		};																				\
201		typedef TYPE Type;																\
202																						\
203		tcu::Vec4 load (glu::CallLogWrapper& gl, int index, const tcu::Vec4& v) const	\
204		{																				\
205			tcu::Vector<TYPE, COMPONENTS> value;										\
206			value = convertToTypeVec<Type, COMPONENTS>(v);								\
207																						\
208			gl.glVertexAttribI ##COMPS ##TYPECODE (index, value.getPtr());				\
209			return convertToTypeVec<float, 4>(value);									\
210		}																				\
211																						\
212		static const char* getCaseName (void)											\
213		{																				\
214			return CASENAME;															\
215		}																				\
216																						\
217		static const char* getName (void)												\
218		{																				\
219			return "VertexAttrib" #COMPS #TYPECODE;										\
220		}																				\
221	}
222
223GEN_DIRECT_FLOAT_LOADER(float, 1, f, "vertex_attrib_1f", (index, value.x()));
224GEN_DIRECT_FLOAT_LOADER(float, 2, f, "vertex_attrib_2f", (index, value.x(), value.y()));
225GEN_DIRECT_FLOAT_LOADER(float, 3, f, "vertex_attrib_3f", (index, value.x(), value.y(), value.z()));
226GEN_DIRECT_FLOAT_LOADER(float, 4, f, "vertex_attrib_4f", (index, value.x(), value.y(), value.z(), value.w()));
227
228GEN_INDIRECT_FLOAT_LOADER(float, 1, fv, "vertex_attrib_1fv");
229GEN_INDIRECT_FLOAT_LOADER(float, 2, fv, "vertex_attrib_2fv");
230GEN_INDIRECT_FLOAT_LOADER(float, 3, fv, "vertex_attrib_3fv");
231GEN_INDIRECT_FLOAT_LOADER(float, 4, fv, "vertex_attrib_4fv");
232
233GEN_DIRECT_INTEGER_LOADER(deInt32, 4, i, "vertex_attribi_4i", (index, value.x(), value.y(), value.z(), value.w()));
234GEN_INDIRECT_INTEGER_LOADER(deInt32, 4, iv, "vertex_attribi_4iv");
235
236GEN_DIRECT_INTEGER_LOADER(deUint32, 4, ui, "vertex_attribi_4ui", (index, value.x(), value.y(), value.z(), value.w()));
237GEN_INDIRECT_INTEGER_LOADER(deUint32, 4, uiv, "vertex_attribi_4uiv");
238
239class AttributeCase : public TestCase
240{
241									AttributeCase			(Context& ctx, const char* name, const char* desc, const char* funcName, bool normalizing, bool useNegative, glu::DataType dataType);
242public:
243	template<typename LoaderType>
244	static AttributeCase*			create					(Context& ctx, glu::DataType dataType);
245									~AttributeCase			(void);
246
247private:
248	void							init					(void);
249	void							deinit					(void);
250	IterateResult					iterate					(void);
251
252	glu::DataType					getTargetType			(void) const;
253	std::string						genVertexSource			(void) const;
254	bool							renderWithValue			(const tcu::Vec4& v);
255	tcu::Vec4						computeColor			(const tcu::Vec4& value);
256	bool							verifyUnicoloredBuffer	(const tcu::Surface& scene, const tcu::Vec4& refValue);
257
258	const bool						m_normalizing;
259	const bool						m_useNegativeValues;
260	const char* const				m_funcName;
261	const glu::DataType				m_dataType;
262	const FloatLoader*				m_loader;
263	glu::ShaderProgram*				m_program;
264	deUint32						m_bufID;
265	bool							m_allIterationsPassed;
266	int								m_iteration;
267
268	enum
269	{
270		RENDER_SIZE = 32
271	};
272};
273
274AttributeCase::AttributeCase (Context& ctx, const char* name, const char* desc, const char* funcName, bool normalizing, bool useNegative, glu::DataType dataType)
275	: TestCase				(ctx, name, desc)
276	, m_normalizing			(normalizing)
277	, m_useNegativeValues	(useNegative)
278	, m_funcName			(funcName)
279	, m_dataType			(dataType)
280	, m_loader				(DE_NULL)
281	, m_program				(DE_NULL)
282	, m_bufID				(0)
283	, m_allIterationsPassed	(true)
284	, m_iteration			(0)
285{
286}
287
288template<typename LoaderType>
289AttributeCase* AttributeCase::create (Context& ctx, glu::DataType dataType)
290{
291	AttributeCase* retVal = new AttributeCase(ctx,
292											  LoaderType::getCaseName(),
293											  (std::string("Test ") + LoaderType::getName()).c_str(),
294											  LoaderType::getName(),
295											  LoaderType::NORMALIZING != 0,
296											  std::numeric_limits<typename LoaderType::Type>::is_signed,
297											  dataType);
298	retVal->m_loader = new LoaderType();
299	return retVal;
300}
301
302AttributeCase::~AttributeCase (void)
303{
304	deinit();
305}
306
307void AttributeCase::init (void)
308{
309	if (m_context.getRenderTarget().getWidth() < RENDER_SIZE || m_context.getRenderTarget().getHeight() < RENDER_SIZE)
310		throw tcu::NotSupportedError("Render target must be at least " + de::toString<int>(RENDER_SIZE) + "x" + de::toString<int>(RENDER_SIZE));
311
312	// log test info
313
314	{
315		const float			maxRange		= (m_normalizing) ? (1.0f) : (s_valueRange);
316		const float			minRange		= (m_useNegativeValues) ? (-maxRange) : (0.0f);
317
318		m_testCtx.getLog()
319			<< tcu::TestLog::Message
320			<< "Loading attribute values using " << m_funcName << "\n"
321			<< "Attribute type: " << glu::getDataTypeName(m_dataType) << "\n"
322			<< "Attribute value range: [" << minRange << ", " << maxRange << "]"
323			<< tcu::TestLog::EndMessage;
324	}
325
326	// gen shader and base quad
327
328	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(genVertexSource()) << glu::FragmentSource(s_passThroughFragmentShaderSource));
329	m_testCtx.getLog() << *m_program;
330	if (!m_program->isOk())
331		throw tcu::TestError("could not build program");
332
333	{
334		const tcu::Vec4 fullscreenQuad[] =
335		{
336			tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
337			tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
338			tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
339			tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
340		};
341
342		const glw::Functions& gl = m_context.getRenderContext().getFunctions();
343
344		gl.genBuffers(1, &m_bufID);
345		gl.bindBuffer(GL_ARRAY_BUFFER, m_bufID);
346		gl.bufferData(GL_ARRAY_BUFFER, sizeof(fullscreenQuad), fullscreenQuad, GL_STATIC_DRAW);
347		GLU_EXPECT_NO_ERROR(gl.getError(), "fill buffer");
348	}
349}
350
351void AttributeCase::deinit (void)
352{
353	delete m_loader;
354	m_loader = DE_NULL;
355
356	delete m_program;
357	m_program = DE_NULL;
358
359	if (m_bufID)
360	{
361		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_bufID);
362		m_bufID = 0;
363	}
364}
365
366AttributeCase::IterateResult AttributeCase::iterate (void)
367{
368	static const tcu::Vec4 testValues[] =
369	{
370		tcu::Vec4(0.0f, 0.5f, 0.2f, 1.0f),
371		tcu::Vec4(0.1f, 0.7f, 1.0f, 0.6f),
372		tcu::Vec4(0.4f, 0.2f, 0.0f, 0.5f),
373		tcu::Vec4(0.5f, 0.0f, 0.9f, 0.1f),
374		tcu::Vec4(0.6f, 0.2f, 0.2f, 0.9f),
375		tcu::Vec4(0.9f, 1.0f, 0.0f, 0.0f),
376		tcu::Vec4(1.0f, 0.5f, 0.3f, 0.8f),
377	};
378
379	const tcu::ScopedLogSection section(m_testCtx.getLog(), "Iteration", "Iteration " + de::toString(m_iteration+1) + "/" + de::toString(DE_LENGTH_OF_ARRAY(testValues)));
380
381	// Test normalizing transfers with whole range, non-normalizing with up to s_valueRange
382	const tcu::Vec4 testValue = ((m_useNegativeValues) ? (testValues[m_iteration] * 2.0f - tcu::Vec4(1.0f)) : (testValues[m_iteration])) * ((m_normalizing) ? (1.0f) : ((float)s_valueRange));
383
384	if (!renderWithValue(testValue))
385		m_allIterationsPassed = false;
386
387	// continue
388
389	if (++m_iteration < DE_LENGTH_OF_ARRAY(testValues))
390		return CONTINUE;
391
392	if (m_allIterationsPassed)
393		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
394	else
395		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got unexpected values");
396
397	return STOP;
398}
399
400std::string AttributeCase::genVertexSource (void) const
401{
402	const int			vectorSize	= (glu::isDataTypeMatrix(m_dataType)) ? (glu::getDataTypeMatrixNumRows(m_dataType)) : (glu::isDataTypeVector(m_dataType)) ? (glu::getDataTypeScalarSize(m_dataType)) : (-1);
403	const char* const	vectorType	= glu::getDataTypeName((glu::isDataTypeMatrix(m_dataType)) ? (glu::getDataTypeVector(glu::TYPE_FLOAT, vectorSize)) : (glu::isDataTypeVector(m_dataType)) ? (glu::getDataTypeVector(glu::TYPE_FLOAT, vectorSize)) : (glu::TYPE_FLOAT));
404	const int			components	= (glu::isDataTypeMatrix(m_dataType)) ? (glu::getDataTypeMatrixNumRows(m_dataType)) : (glu::getDataTypeScalarSize(m_dataType));
405	std::ostringstream	buf;
406
407	buf <<	"#version 300 es\n"
408			"in highp vec4 a_position;\n"
409			"in highp " << glu::getDataTypeName(m_dataType) << " a_value;\n"
410			"out highp vec4 v_color;\n"
411			"void main (void)\n"
412			"{\n"
413			"	gl_Position = a_position;\n"
414			"\n";
415
416	if (m_normalizing)
417		buf << "	highp " << vectorType << " normalizedValue = " << ((glu::getDataTypeScalarType(m_dataType) == glu::TYPE_FLOAT) ? ("") : (vectorType)) << "(a_value" << ((glu::isDataTypeMatrix(m_dataType)) ? ("[1]") : ("")) << ");\n";
418	else
419		buf << "	highp " << vectorType << " normalizedValue = " << ((glu::getDataTypeScalarType(m_dataType) == glu::TYPE_FLOAT) ? ("") : (vectorType)) << "(a_value" << ((glu::isDataTypeMatrix(m_dataType)) ? ("[1]") : ("")) << ") / float(" << s_valueRange << ");\n";
420
421	if (m_useNegativeValues)
422		buf << "	highp " << vectorType << " positiveNormalizedValue = (normalizedValue + " << vectorType << "(1.0)) / 2.0;\n";
423	else
424		buf << "	highp " << vectorType << " positiveNormalizedValue = normalizedValue;\n";
425
426	if (components == 1)
427		buf << "	v_color = vec4(positiveNormalizedValue, 0.0, 0.0, 1.0);\n";
428	else if (components == 2)
429		buf << "	v_color = vec4(positiveNormalizedValue.xy, 0.0, 1.0);\n";
430	else if (components == 3)
431		buf << "	v_color = vec4(positiveNormalizedValue.xyz, 1.0);\n";
432	else if (components == 4)
433		buf << "	v_color = vec4((positiveNormalizedValue.xy + positiveNormalizedValue.zz) / 2.0, positiveNormalizedValue.w, 1.0);\n";
434	else
435		DE_ASSERT(DE_FALSE);
436
437	buf << "}\n";
438
439	return buf.str();
440}
441
442bool AttributeCase::renderWithValue (const tcu::Vec4& v)
443{
444	glu::CallLogWrapper	gl				(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
445
446	gl.enableLogging(true);
447
448	const int			positionIndex	= gl.glGetAttribLocation(m_program->getProgram(), "a_position");
449	const int			valueIndex		= gl.glGetAttribLocation(m_program->getProgram(), "a_value");
450	tcu::Surface		dest			(RENDER_SIZE, RENDER_SIZE);
451	tcu::Vec4			loadedValue;
452
453	gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
454	gl.glClear(GL_COLOR_BUFFER_BIT);
455	gl.glViewport(0, 0, RENDER_SIZE, RENDER_SIZE);
456	GLU_EXPECT_NO_ERROR(gl.glGetError(), "setup");
457
458	gl.glBindBuffer(GL_ARRAY_BUFFER, m_bufID);
459	gl.glVertexAttribPointer(positionIndex, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
460	gl.glEnableVertexAttribArray(positionIndex);
461	GLU_EXPECT_NO_ERROR(gl.glGetError(), "position va");
462
463	// transfer test value. Load to the second column in the matrix case
464	loadedValue = m_loader->load(gl, (glu::isDataTypeMatrix(m_dataType)) ? (valueIndex + 1) : (valueIndex), v);
465	GLU_EXPECT_NO_ERROR(gl.glGetError(), "default va");
466
467	gl.glUseProgram(m_program->getProgram());
468	gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
469	gl.glUseProgram(0);
470	GLU_EXPECT_NO_ERROR(gl.glGetError(), "draw");
471
472	glu::readPixels(m_context.getRenderContext(), 0, 0, dest.getAccess());
473
474	// check whole result is colored correctly
475	return verifyUnicoloredBuffer(dest, computeColor(loadedValue));
476}
477
478tcu::Vec4 AttributeCase::computeColor (const tcu::Vec4& value)
479{
480	const tcu::Vec4 normalizedValue			= value / ((m_normalizing) ? (1.0f) : ((float)s_valueRange));
481	const tcu::Vec4 positiveNormalizedValue = ((m_useNegativeValues) ? ((normalizedValue + tcu::Vec4(1.0f)) / 2.0f) : (normalizedValue));
482	const int		components				= (glu::isDataTypeMatrix(m_dataType)) ? (glu::getDataTypeMatrixNumRows(m_dataType)) : (glu::getDataTypeScalarSize(m_dataType));
483
484	if (components == 1)
485		return tcu::Vec4(positiveNormalizedValue.x(), 0.0f, 0.0f, 1.0f);
486	else if (components == 2)
487		return tcu::Vec4(positiveNormalizedValue.x(), positiveNormalizedValue.y(), 0.0f, 1.0f);
488	else if (components == 3)
489		return tcu::Vec4(positiveNormalizedValue.x(), positiveNormalizedValue.y(), positiveNormalizedValue.z(), 1.0f);
490	else if (components == 4)
491		return tcu::Vec4((positiveNormalizedValue.x() + positiveNormalizedValue.z()) / 2.0f, (positiveNormalizedValue.y() + positiveNormalizedValue.z()) / 2.0f, positiveNormalizedValue.w(), 1.0f);
492	else
493		DE_ASSERT(DE_FALSE);
494
495	return tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
496}
497
498bool AttributeCase::verifyUnicoloredBuffer (const tcu::Surface& scene, const tcu::Vec4& refValue)
499{
500	tcu::Surface	errorMask		(RENDER_SIZE, RENDER_SIZE);
501	const tcu::RGBA	refColor		(refValue);
502	const int		resultThreshold	= 2;
503	const tcu::RGBA	colorThreshold	= m_context.getRenderTarget().getPixelFormat().getColorThreshold() * resultThreshold;
504	bool			error			= false;
505
506	tcu::RGBA		exampleColor;
507	tcu::IVec2		examplePos;
508
509	tcu::clear(errorMask.getAccess(), tcu::RGBA::green.toIVec());
510
511	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying rendered image. Expecting color " << refColor << ", threshold " << colorThreshold << tcu::TestLog::EndMessage;
512
513	for (int y = 0; y < RENDER_SIZE; ++y)
514	for (int x = 0; x < RENDER_SIZE; ++x)
515	{
516		const tcu::RGBA color = scene.getPixel(x, y);
517
518		if (de::abs(color.getRed()   - refColor.getRed())   > colorThreshold.getRed()   ||
519			de::abs(color.getGreen() - refColor.getGreen()) > colorThreshold.getGreen() ||
520			de::abs(color.getBlue()  - refColor.getBlue())  > colorThreshold.getBlue())
521		{
522			// first error
523			if (!error)
524			{
525				exampleColor = color;
526				examplePos = tcu::IVec2(x, y);
527			}
528
529			error = true;
530			errorMask.setPixel(x, y, tcu::RGBA::red);
531		}
532	}
533
534	if (!error)
535		m_testCtx.getLog() << tcu::TestLog::Message << "Rendered image is valid." << tcu::TestLog::EndMessage;
536	else
537	{
538		m_testCtx.getLog()	<< tcu::TestLog::Message
539							<< "Found invalid pixel(s).\n"
540							<< "Pixel at (" << examplePos.x() << ", " << examplePos.y() << ") color: " << exampleColor
541							<< tcu::TestLog::EndMessage
542							<< tcu::TestLog::ImageSet("Result", "Render result")
543							<< tcu::TestLog::Image("Result", "Result", scene)
544							<< tcu::TestLog::Image("ErrorMask", "Error Mask", errorMask)
545							<< tcu::TestLog::EndImageSet;
546	}
547
548	return !error;
549}
550
551} // anonymous
552
553DefaultVertexAttributeTests::DefaultVertexAttributeTests (Context& context)
554	: TestCaseGroup(context, "default_vertex_attrib", "Test default vertex attributes")
555{
556}
557
558DefaultVertexAttributeTests::~DefaultVertexAttributeTests (void)
559{
560}
561
562void DefaultVertexAttributeTests::init (void)
563{
564	struct Target
565	{
566		const char*		name;
567		glu::DataType	dataType;
568		bool			reducedTestSets;	// !< use reduced coverage
569	};
570
571	static const Target floatTargets[] =
572	{
573		{ "float",	glu::TYPE_FLOAT,		false	},
574		{ "vec2",	glu::TYPE_FLOAT_VEC2,	true	},
575		{ "vec3",	glu::TYPE_FLOAT_VEC3,	true	},
576		{ "vec4",	glu::TYPE_FLOAT_VEC4,	false	},
577		{ "mat2",	glu::TYPE_FLOAT_MAT2,	true	},
578		{ "mat2x3",	glu::TYPE_FLOAT_MAT2X3,	true	},
579		{ "mat2x4",	glu::TYPE_FLOAT_MAT2X4,	true	},
580		{ "mat3",	glu::TYPE_FLOAT_MAT3,	true	},
581		{ "mat3x2",	glu::TYPE_FLOAT_MAT3X2,	true	},
582		{ "mat3x4",	glu::TYPE_FLOAT_MAT3X4,	true	},
583		{ "mat4",	glu::TYPE_FLOAT_MAT4,	false	},
584		{ "mat4x2",	glu::TYPE_FLOAT_MAT4X2,	true	},
585		{ "mat4x3",	glu::TYPE_FLOAT_MAT4X3,	true	},
586	};
587
588	static const Target intTargets[] =
589	{
590		{ "int",	glu::TYPE_INT,			false	},
591		{ "ivec2",	glu::TYPE_INT_VEC2,		true	},
592		{ "ivec3",	glu::TYPE_INT_VEC3,		true	},
593		{ "ivec4",	glu::TYPE_INT_VEC4,		false	},
594	};
595
596	static const Target uintTargets[] =
597	{
598		{ "uint",	glu::TYPE_UINT,			false	},
599		{ "uvec2",	glu::TYPE_UINT_VEC2,	true	},
600		{ "uvec3",	glu::TYPE_UINT_VEC3,	true	},
601		{ "uvec4",	glu::TYPE_UINT_VEC4,	false	},
602	};
603
604	// float targets
605
606	for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(floatTargets); ++targetNdx)
607	{
608		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, floatTargets[targetNdx].name, (std::string("test with ") + floatTargets[targetNdx].name).c_str());
609		const bool					fullSet	= !floatTargets[targetNdx].reducedTestSets;
610
611#define ADD_CASE(X) group->addChild(AttributeCase::create<X>(m_context, floatTargets[targetNdx].dataType))
612#define ADD_REDUCED_CASE(X)	if (fullSet) ADD_CASE(X)
613
614		ADD_CASE		(LoaderVertexAttrib1f);
615		ADD_REDUCED_CASE(LoaderVertexAttrib2f);
616		ADD_REDUCED_CASE(LoaderVertexAttrib3f);
617		ADD_CASE		(LoaderVertexAttrib4f);
618
619		ADD_CASE		(LoaderVertexAttrib1fv);
620		ADD_REDUCED_CASE(LoaderVertexAttrib2fv);
621		ADD_REDUCED_CASE(LoaderVertexAttrib3fv);
622		ADD_CASE		(LoaderVertexAttrib4fv);
623
624#undef ADD_CASE
625#undef ADD_REDUCED_CASE
626
627		addChild(group);
628	}
629
630	// int targets
631
632	for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(intTargets); ++targetNdx)
633	{
634		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, intTargets[targetNdx].name, (std::string("test with ") + intTargets[targetNdx].name).c_str());
635
636#define ADD_CASE(X) group->addChild(AttributeCase::create<X>(m_context, intTargets[targetNdx].dataType))
637
638		ADD_CASE		(LoaderVertexAttribI4i);
639		ADD_CASE		(LoaderVertexAttribI4iv);
640
641#undef ADD_CASE
642
643		addChild(group);
644	}
645
646	// uint targets
647
648	for (int targetNdx = 0; targetNdx < DE_LENGTH_OF_ARRAY(uintTargets); ++targetNdx)
649	{
650		tcu::TestCaseGroup* const	group	= new tcu::TestCaseGroup(m_testCtx, uintTargets[targetNdx].name, (std::string("test with ") + uintTargets[targetNdx].name).c_str());
651
652#define ADD_CASE(X) group->addChild(AttributeCase::create<X>(m_context, uintTargets[targetNdx].dataType))
653
654		ADD_CASE		(LoaderVertexAttribI4ui);
655		ADD_CASE		(LoaderVertexAttribI4uiv);
656
657#undef ADD_CASE
658
659		addChild(group);
660	}
661}
662
663} // Functional
664} // gles3
665} // deqp
666