Home | History | Annotate | Download | only in functional
      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 
     42 namespace deqp
     43 {
     44 namespace gles3
     45 {
     46 namespace Functional
     47 {
     48 namespace
     49 {
     50 
     51 static const int s_valueRange = 10;
     52 
     53 static 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 
     61 template <typename T1, int S1, typename T2, int S2>
     62 tcu::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 
     78 class FloatLoader
     79 {
     80 public:
     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 
    223 GEN_DIRECT_FLOAT_LOADER(float, 1, f, "vertex_attrib_1f", (index, value.x()));
    224 GEN_DIRECT_FLOAT_LOADER(float, 2, f, "vertex_attrib_2f", (index, value.x(), value.y()));
    225 GEN_DIRECT_FLOAT_LOADER(float, 3, f, "vertex_attrib_3f", (index, value.x(), value.y(), value.z()));
    226 GEN_DIRECT_FLOAT_LOADER(float, 4, f, "vertex_attrib_4f", (index, value.x(), value.y(), value.z(), value.w()));
    227 
    228 GEN_INDIRECT_FLOAT_LOADER(float, 1, fv, "vertex_attrib_1fv");
    229 GEN_INDIRECT_FLOAT_LOADER(float, 2, fv, "vertex_attrib_2fv");
    230 GEN_INDIRECT_FLOAT_LOADER(float, 3, fv, "vertex_attrib_3fv");
    231 GEN_INDIRECT_FLOAT_LOADER(float, 4, fv, "vertex_attrib_4fv");
    232 
    233 GEN_DIRECT_INTEGER_LOADER(deInt32, 4, i, "vertex_attribi_4i", (index, value.x(), value.y(), value.z(), value.w()));
    234 GEN_INDIRECT_INTEGER_LOADER(deInt32, 4, iv, "vertex_attribi_4iv");
    235 
    236 GEN_DIRECT_INTEGER_LOADER(deUint32, 4, ui, "vertex_attribi_4ui", (index, value.x(), value.y(), value.z(), value.w()));
    237 GEN_INDIRECT_INTEGER_LOADER(deUint32, 4, uiv, "vertex_attribi_4uiv");
    238 
    239 class AttributeCase : public TestCase
    240 {
    241 									AttributeCase			(Context& ctx, const char* name, const char* desc, const char* funcName, bool normalizing, bool useNegative, glu::DataType dataType);
    242 public:
    243 	template<typename LoaderType>
    244 	static AttributeCase*			create					(Context& ctx, glu::DataType dataType);
    245 									~AttributeCase			(void);
    246 
    247 private:
    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 
    274 AttributeCase::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 
    288 template<typename LoaderType>
    289 AttributeCase* 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 
    302 AttributeCase::~AttributeCase (void)
    303 {
    304 	deinit();
    305 }
    306 
    307 void 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 
    351 void 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 
    366 AttributeCase::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 
    400 std::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 
    442 bool 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 
    478 tcu::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 
    498 bool 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 
    553 DefaultVertexAttributeTests::DefaultVertexAttributeTests (Context& context)
    554 	: TestCaseGroup(context, "default_vertex_attrib", "Test default vertex attributes")
    555 {
    556 }
    557 
    558 DefaultVertexAttributeTests::~DefaultVertexAttributeTests (void)
    559 {
    560 }
    561 
    562 void 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