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 Instanced rendering tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es3fInstancedRenderingTests.hpp"
     25 #include "gluPixelTransfer.hpp"
     26 #include "gluShaderProgram.hpp"
     27 #include "gluShaderUtil.hpp"
     28 #include "tcuTestLog.hpp"
     29 #include "tcuSurface.hpp"
     30 #include "tcuImageCompare.hpp"
     31 #include "tcuVector.hpp"
     32 #include "tcuRenderTarget.hpp"
     33 #include "deRandom.hpp"
     34 #include "deStringUtil.hpp"
     35 #include "deString.h"
     36 
     37 #include "glw.h"
     38 
     39 using std::vector;
     40 using std::string;
     41 
     42 namespace deqp
     43 {
     44 namespace gles3
     45 {
     46 namespace Functional
     47 {
     48 
     49 static const int	MAX_RENDER_WIDTH		= 128;
     50 static const int	MAX_RENDER_HEIGHT		= 128;
     51 
     52 static const int	QUAD_GRID_SIZE			= 127;
     53 
     54 // Attribute divisors for the attributes defining the color's RGB components.
     55 static const int	ATTRIB_DIVISOR_R		= 3;
     56 static const int	ATTRIB_DIVISOR_G		= 2;
     57 static const int	ATTRIB_DIVISOR_B		= 1;
     58 
     59 static const int	OFFSET_COMPONENTS		= 3; // \note Affects whether a float or a vecN is used in shader, but only first component is non-zero.
     60 
     61 // Scale and bias values when converting float to integer, when attribute is of integer type.
     62 static const float	FLOAT_INT_SCALE			= 100.0f;
     63 static const float	FLOAT_INT_BIAS			= -50.0f;
     64 static const float	FLOAT_UINT_SCALE		= 100.0f;
     65 static const float	FLOAT_UINT_BIAS			= 0.0f;
     66 
     67 // \note Non-anonymous namespace needed; VarComp is used as a template parameter.
     68 namespace vcns
     69 {
     70 
     71 union VarComp
     72 {
     73 	float		f32;
     74 	deUint32	u32;
     75 	deInt32		i32;
     76 
     77 	VarComp(float v)	: f32(v) {}
     78 	VarComp(deUint32 v)	: u32(v) {}
     79 	VarComp(deInt32 v)	: i32(v) {}
     80 };
     81 DE_STATIC_ASSERT(sizeof(VarComp) == sizeof(deUint32));
     82 
     83 } // vcns
     84 
     85 using namespace vcns;
     86 
     87 class InstancedRenderingCase : public TestCase
     88 {
     89 public:
     90 	enum DrawFunction
     91 	{
     92 		FUNCTION_DRAW_ARRAYS_INSTANCED = 0,
     93 		FUNCTION_DRAW_ELEMENTS_INSTANCED,
     94 
     95 		FUNCTION_LAST
     96 	};
     97 
     98 	enum InstancingType
     99 	{
    100 		TYPE_INSTANCE_ID = 0,
    101 		TYPE_ATTRIB_DIVISOR,
    102 		TYPE_MIXED,
    103 
    104 		TYPE_LAST
    105 	};
    106 
    107 								InstancedRenderingCase	(Context& context, const char* name, const char* description, DrawFunction function, InstancingType instancingType, glu::DataType rgbAttrType, int numInstances);
    108 								~InstancedRenderingCase	(void);
    109 
    110 	void						init					(void);
    111 	void						deinit					(void);
    112 	IterateResult				iterate					(void);
    113 
    114 private:
    115 								InstancedRenderingCase	(const InstancedRenderingCase& other);
    116 	InstancedRenderingCase&		operator=				(const InstancedRenderingCase& other);
    117 
    118 	void						pushVarCompAttrib		(vector<VarComp>& vec, float val);
    119 
    120 	void						setupVarAttribPointer	(const void* attrPtr, int startLocation, int divisor);
    121 	void						setupAndRender			(void);
    122 	void						computeReference		(tcu::Surface& dst);
    123 
    124 	DrawFunction				m_function;
    125 	InstancingType				m_instancingType;
    126 	glu::DataType				m_rgbAttrType;			// \note Instance attribute types, color components only. Position offset attribute is always float/vecN.
    127 	int							m_numInstances;
    128 
    129 	vector<float>				m_gridVertexPositions;	// X and Y components per vertex.
    130 	vector<deUint16>			m_gridIndices;			// \note Only used if m_function is FUNCTION_DRAW_ELEMENTS_INSTANCED.
    131 
    132 	// \note Some or all of the following instance attribute parameters may be unused with TYPE_INSTANCE_ID or TYPE_MIXED.
    133 	vector<float>				m_instanceOffsets;		// Position offsets. OFFSET_COMPONENTS components per offset.
    134 	// Attribute data for float, int or uint (or respective vector types) color components.
    135 	vector<VarComp>				m_instanceColorR;
    136 	vector<VarComp>				m_instanceColorG;
    137 	vector<VarComp>				m_instanceColorB;
    138 
    139 	glu::ShaderProgram*			m_program;
    140 };
    141 
    142 InstancedRenderingCase::InstancedRenderingCase (Context& context, const char* name, const char* description, DrawFunction function, InstancingType instancingType, glu::DataType rgbAttrType, int numInstances)
    143 	: TestCase			(context, name, description)
    144 	, m_function		(function)
    145 	, m_instancingType	(instancingType)
    146 	, m_rgbAttrType		(rgbAttrType)
    147 	, m_numInstances	(numInstances)
    148 	, m_program			(DE_NULL)
    149 {
    150 }
    151 
    152 InstancedRenderingCase::~InstancedRenderingCase (void)
    153 {
    154 	InstancedRenderingCase::deinit();
    155 }
    156 
    157 // Helper function that does biasing and scaling when converting float to integer.
    158 void InstancedRenderingCase::pushVarCompAttrib (vector<VarComp>& vec, float val)
    159 {
    160 	bool	isFloatCase	= glu::isDataTypeFloatOrVec(m_rgbAttrType);
    161 	bool	isIntCase	= glu::isDataTypeIntOrIVec(m_rgbAttrType);
    162 	bool	isUintCase	= glu::isDataTypeUintOrUVec(m_rgbAttrType);
    163 	bool	isMatCase	= glu::isDataTypeMatrix(m_rgbAttrType);
    164 
    165 	if (isFloatCase || isMatCase)
    166 		vec.push_back(VarComp(val));
    167 	else if (isIntCase)
    168 		vec.push_back(VarComp((deInt32)(val*FLOAT_INT_SCALE + FLOAT_INT_BIAS)));
    169 	else if (isUintCase)
    170 		vec.push_back(VarComp((deUint32)(val*FLOAT_UINT_SCALE + FLOAT_UINT_BIAS)));
    171 	else
    172 		DE_ASSERT(DE_FALSE);
    173 }
    174 
    175 void InstancedRenderingCase::init (void)
    176 {
    177 	bool	isFloatCase			= glu::isDataTypeFloatOrVec(m_rgbAttrType);
    178 	bool	isIntCase			= glu::isDataTypeIntOrIVec(m_rgbAttrType);
    179 	bool	isUintCase			= glu::isDataTypeUintOrUVec(m_rgbAttrType);
    180 	bool	isMatCase			= glu::isDataTypeMatrix(m_rgbAttrType);
    181 	int		typeSize			= glu::getDataTypeScalarSize(m_rgbAttrType);
    182 	bool	isScalarCase		= typeSize == 1;
    183 	string	swizzleFirst		= isScalarCase ? "" : ".x";
    184 	string	typeName			= glu::getDataTypeName(m_rgbAttrType);
    185 
    186 	string	floatIntScaleStr	= "(" + de::floatToString(FLOAT_INT_SCALE, 3) + ")";
    187 	string	floatIntBiasStr		= "(" + de::floatToString(FLOAT_INT_BIAS, 3) + ")";
    188 	string	floatUintScaleStr	= "(" + de::floatToString(FLOAT_UINT_SCALE, 3) + ")";
    189 	string	floatUintBiasStr	= "(" + de::floatToString(FLOAT_UINT_BIAS, 3) + ")";
    190 
    191 	DE_ASSERT(isFloatCase || isIntCase || isUintCase || isMatCase);
    192 
    193 	// Generate shader.
    194 	// \note For case TYPE_MIXED, vertex position offset and color red component get their values from instance id, while green and blue get their values from instanced attributes.
    195 
    196 	string numInstancesStr = de::toString(m_numInstances) + ".0";
    197 
    198 	string instanceAttribs;
    199 	string posExpression;
    200 	string colorRExpression;
    201 	string colorGExpression;
    202 	string colorBExpression;
    203 
    204 	if (m_instancingType == TYPE_INSTANCE_ID || m_instancingType == TYPE_MIXED)
    205 	{
    206 		posExpression = "a_position + vec4(float(gl_InstanceID) * 2.0 / " + numInstancesStr + ", 0.0, 0.0, 0.0)";
    207 		colorRExpression = "float(gl_InstanceID)/" + numInstancesStr;
    208 
    209 		if (m_instancingType == TYPE_INSTANCE_ID)
    210 		{
    211 			colorGExpression = "float(gl_InstanceID)*2.0/" + numInstancesStr;
    212 			colorBExpression = "1.0 - float(gl_InstanceID)/" + numInstancesStr;
    213 		}
    214 	}
    215 
    216 	if (m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED)
    217 	{
    218 		if (m_instancingType == TYPE_ATTRIB_DIVISOR)
    219 		{
    220 			posExpression = "a_position + vec4(a_instanceOffset";
    221 
    222 			DE_STATIC_ASSERT(OFFSET_COMPONENTS >= 1 && OFFSET_COMPONENTS <= 4);
    223 
    224 			for (int i = 0; i < 4-OFFSET_COMPONENTS; i++)
    225 				posExpression += ", 0.0";
    226 			posExpression += ")";
    227 
    228 			if (isFloatCase)
    229 				colorRExpression = "a_instanceR" + swizzleFirst;
    230 			else if (isIntCase)
    231 				colorRExpression = "(float(a_instanceR" + swizzleFirst + ") - " + floatIntBiasStr + ") / " + floatIntScaleStr;
    232 			else if (isUintCase)
    233 				colorRExpression = "(float(a_instanceR" + swizzleFirst + ") - " + floatUintBiasStr + ") / " + floatUintScaleStr;
    234 			else if (isMatCase)
    235 				colorRExpression = "a_instanceR[0][0]";
    236 			else
    237 				DE_ASSERT(DE_FALSE);
    238 
    239 			instanceAttribs += "in highp " + (OFFSET_COMPONENTS == 1 ? string("float") : "vec" + de::toString(OFFSET_COMPONENTS)) + " a_instanceOffset;\n";
    240 			instanceAttribs += "in mediump " + typeName + " a_instanceR;\n";
    241 		}
    242 
    243 		if (isFloatCase)
    244 		{
    245 			colorGExpression = "a_instanceG" + swizzleFirst;
    246 			colorBExpression = "a_instanceB" + swizzleFirst;
    247 		}
    248 		else if (isIntCase)
    249 		{
    250 			colorGExpression = "(float(a_instanceG" + swizzleFirst + ") - " + floatIntBiasStr + ") / " + floatIntScaleStr;
    251 			colorBExpression = "(float(a_instanceB" + swizzleFirst + ") - " + floatIntBiasStr + ") / " + floatIntScaleStr;
    252 		}
    253 		else if (isUintCase)
    254 		{
    255 			colorGExpression = "(float(a_instanceG" + swizzleFirst + ") - " + floatUintBiasStr + ") / " + floatUintScaleStr;
    256 			colorBExpression = "(float(a_instanceB" + swizzleFirst + ") - " + floatUintBiasStr + ") / " + floatUintScaleStr;
    257 		}
    258 		else if (isMatCase)
    259 		{
    260 			colorGExpression = "a_instanceG[0][0]";
    261 			colorBExpression = "a_instanceB[0][0]";
    262 		}
    263 		else
    264 			DE_ASSERT(DE_FALSE);
    265 
    266 		instanceAttribs += "in mediump " + typeName + " a_instanceG;\n";
    267 		instanceAttribs += "in mediump " + typeName + " a_instanceB;\n";
    268 	}
    269 
    270 	DE_ASSERT(!posExpression.empty());
    271 	DE_ASSERT(!colorRExpression.empty());
    272 	DE_ASSERT(!colorGExpression.empty());
    273 	DE_ASSERT(!colorBExpression.empty());
    274 
    275 	std::string vertShaderSourceStr =
    276 		"#version 300 es\n"
    277 		"in highp vec4 a_position;\n" +
    278 		instanceAttribs +
    279 		"out mediump vec4 v_color;\n"
    280 		"\n"
    281 		"void main()\n"
    282 		"{\n"
    283 		"	gl_Position = " + posExpression + ";\n"
    284 		"	v_color.r = " + colorRExpression + ";\n"
    285 		"	v_color.g = " + colorGExpression + ";\n"
    286 		"	v_color.b = " + colorBExpression + ";\n"
    287 		"	v_color.a = 1.0;\n"
    288 		"}\n";
    289 
    290 	static const char* fragShaderSource =
    291 		"#version 300 es\n"
    292 		"layout(location = 0) out mediump vec4 o_color;\n"
    293 		"in mediump vec4 v_color;\n"
    294 		"\n"
    295 		"void main()\n"
    296 		"{\n"
    297 		"	o_color = v_color;\n"
    298 		"}\n";
    299 
    300 	// Create shader program and log it.
    301 
    302 	DE_ASSERT(!m_program);
    303 	m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertShaderSourceStr, fragShaderSource));
    304 
    305 	tcu::TestLog& log = m_testCtx.getLog();
    306 
    307 	log << *m_program;
    308 
    309 	if(!m_program->isOk())
    310 		TCU_FAIL("Failed to compile shader");
    311 
    312 	// Vertex shader attributes.
    313 
    314 	if (m_function == FUNCTION_DRAW_ELEMENTS_INSTANCED)
    315 	{
    316 		// Vertex positions. Positions form a vertical bar of width <screen width>/<number of instances>.
    317 
    318 		for (int y = 0; y < QUAD_GRID_SIZE + 1; y++)
    319 			for (int x = 0; x < QUAD_GRID_SIZE + 1; x++)
    320 			{
    321 				float fx = -1.0f + (float)x / (float)QUAD_GRID_SIZE * 2.0f / (float)m_numInstances;
    322 				float fy = -1.0f + (float)y / (float)QUAD_GRID_SIZE * 2.0f;
    323 
    324 				m_gridVertexPositions.push_back(fx);
    325 				m_gridVertexPositions.push_back(fy);
    326 			}
    327 
    328 		// Indices.
    329 
    330 		for (int y = 0; y < QUAD_GRID_SIZE; y++)
    331 			for (int x = 0; x < QUAD_GRID_SIZE; x++)
    332 			{
    333 				int ndx00 = y*(QUAD_GRID_SIZE + 1) + x;
    334 				int ndx10 = y*(QUAD_GRID_SIZE + 1) + x + 1;
    335 				int ndx01 = (y + 1)*(QUAD_GRID_SIZE + 1) + x;
    336 				int ndx11 = (y + 1)*(QUAD_GRID_SIZE + 1) + x + 1;
    337 
    338 				// Lower-left triangle of a quad.
    339 				m_gridIndices.push_back(ndx00);
    340 				m_gridIndices.push_back(ndx10);
    341 				m_gridIndices.push_back(ndx01);
    342 
    343 				// Upper-right triangle of a quad.
    344 				m_gridIndices.push_back(ndx11);
    345 				m_gridIndices.push_back(ndx01);
    346 				m_gridIndices.push_back(ndx10);
    347 			}
    348 	}
    349 	else
    350 	{
    351 		DE_ASSERT(m_function == FUNCTION_DRAW_ARRAYS_INSTANCED);
    352 
    353 		// Vertex positions. Positions form a vertical bar of width <screen width>/<number of instances>.
    354 
    355 		for (int y = 0; y < QUAD_GRID_SIZE; y++)
    356 			for (int x = 0; x < QUAD_GRID_SIZE; x++)
    357 			{
    358 				float fx0 = -1.0f + (float)(x+0) / (float)QUAD_GRID_SIZE * 2.0f / (float)m_numInstances;
    359 				float fx1 = -1.0f + (float)(x+1) / (float)QUAD_GRID_SIZE * 2.0f / (float)m_numInstances;
    360 				float fy0 = -1.0f + (float)(y+0) / (float)QUAD_GRID_SIZE * 2.0f;
    361 				float fy1 = -1.0f + (float)(y+1) / (float)QUAD_GRID_SIZE * 2.0f;
    362 
    363 				// Vertices of a quad's lower-left triangle: (fx0, fy0), (fx1, fy0) and (fx0, fy1)
    364 				m_gridVertexPositions.push_back(fx0);
    365 				m_gridVertexPositions.push_back(fy0);
    366 				m_gridVertexPositions.push_back(fx1);
    367 				m_gridVertexPositions.push_back(fy0);
    368 				m_gridVertexPositions.push_back(fx0);
    369 				m_gridVertexPositions.push_back(fy1);
    370 
    371 				// Vertices of a quad's upper-right triangle: (fx1, fy1), (fx0, fy1) and (fx1, fy0)
    372 				m_gridVertexPositions.push_back(fx1);
    373 				m_gridVertexPositions.push_back(fy1);
    374 				m_gridVertexPositions.push_back(fx0);
    375 				m_gridVertexPositions.push_back(fy1);
    376 				m_gridVertexPositions.push_back(fx1);
    377 				m_gridVertexPositions.push_back(fy0);
    378 			}
    379 	}
    380 
    381 	// Instanced attributes: position offset and color RGB components.
    382 
    383 	if (m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED)
    384 	{
    385 		if (m_instancingType == TYPE_ATTRIB_DIVISOR)
    386 		{
    387 			// Offsets are such that the vertical bars are drawn next to each other.
    388 			for (int i = 0; i < m_numInstances; i++)
    389 			{
    390 				m_instanceOffsets.push_back((float)i * 2.0f / (float)m_numInstances);
    391 
    392 				DE_STATIC_ASSERT(OFFSET_COMPONENTS >= 1 && OFFSET_COMPONENTS <= 4);
    393 
    394 				for (int j = 0; j < OFFSET_COMPONENTS-1; j++)
    395 					m_instanceOffsets.push_back(0.0f);
    396 			}
    397 
    398 			int rInstances = m_numInstances / ATTRIB_DIVISOR_R + (m_numInstances % ATTRIB_DIVISOR_R == 0 ? 0 : 1);
    399 			for (int i = 0; i < rInstances; i++)
    400 			{
    401 				pushVarCompAttrib(m_instanceColorR, (float)i / (float)rInstances);
    402 
    403 				for (int j = 0; j < typeSize - 1; j++)
    404 					pushVarCompAttrib(m_instanceColorR, 0.0f);
    405 			}
    406 		}
    407 
    408 		int gInstances = m_numInstances / ATTRIB_DIVISOR_G + (m_numInstances % ATTRIB_DIVISOR_G == 0 ? 0 : 1);
    409 		for (int i = 0; i < gInstances; i++)
    410 		{
    411 			pushVarCompAttrib(m_instanceColorG, (float)i*2.0f / (float)gInstances);
    412 
    413 			for (int j = 0; j < typeSize - 1; j++)
    414 				pushVarCompAttrib(m_instanceColorG, 0.0f);
    415 		}
    416 
    417 		int bInstances = m_numInstances / ATTRIB_DIVISOR_B + (m_numInstances % ATTRIB_DIVISOR_B == 0 ? 0 : 1);
    418 		for (int i = 0; i < bInstances; i++)
    419 		{
    420 			pushVarCompAttrib(m_instanceColorB, 1.0f - (float)i / (float)bInstances);
    421 
    422 			for (int j = 0; j < typeSize - 1; j++)
    423 				pushVarCompAttrib(m_instanceColorB, 0.0f);
    424 		}
    425 	}
    426 }
    427 
    428 void InstancedRenderingCase::deinit (void)
    429 {
    430 	delete m_program;
    431 	m_program = DE_NULL;
    432 }
    433 
    434 InstancedRenderingCase::IterateResult InstancedRenderingCase::iterate (void)
    435 {
    436 	int							width			= deMin32(m_context.getRenderTarget().getWidth(), MAX_RENDER_WIDTH);
    437 	int							height			= deMin32(m_context.getRenderTarget().getHeight(), MAX_RENDER_HEIGHT);
    438 
    439 	int							xOffsetMax		= m_context.getRenderTarget().getWidth() - width;
    440 	int							yOffsetMax		= m_context.getRenderTarget().getHeight() - height;
    441 
    442 	de::Random					rnd				(deStringHash(getName()));
    443 
    444 	int							xOffset			= rnd.getInt(0, xOffsetMax);
    445 	int							yOffset			= rnd.getInt(0, yOffsetMax);
    446 	tcu::Surface				referenceImg	(width, height);
    447 	tcu::Surface				resultImg		(width, height);
    448 
    449 	// Draw result.
    450 
    451 	glViewport(xOffset, yOffset, width, height);
    452 
    453 	setupAndRender();
    454 
    455 	glu::readPixels(m_context.getRenderContext(), xOffset, yOffset, resultImg.getAccess());
    456 
    457 	// Compute reference.
    458 
    459 	computeReference(referenceImg);
    460 
    461 	// Compare.
    462 
    463 	bool testOk = tcu::fuzzyCompare(m_testCtx.getLog(), "ComparisonResult", "Image comparison result", referenceImg, resultImg, 0.05f, tcu::COMPARE_LOG_RESULT);
    464 
    465 	m_testCtx.setTestResult(testOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    466 							testOk ? "Pass"					: "Fail");
    467 
    468 	return STOP;
    469 }
    470 
    471 void InstancedRenderingCase::setupVarAttribPointer (const void* attrPtr, int location, int divisor)
    472 {
    473 	bool	isFloatCase		= glu::isDataTypeFloatOrVec(m_rgbAttrType);
    474 	bool	isIntCase		= glu::isDataTypeIntOrIVec(m_rgbAttrType);
    475 	bool	isUintCase		= glu::isDataTypeUintOrUVec(m_rgbAttrType);
    476 	bool	isMatCase		= glu::isDataTypeMatrix(m_rgbAttrType);
    477 	int		typeSize		= glu::getDataTypeScalarSize(m_rgbAttrType);
    478 	int		numSlots		= isMatCase ? glu::getDataTypeMatrixNumColumns(m_rgbAttrType) : 1; // Matrix uses as many attribute slots as it has columns.
    479 
    480 	for (int slotNdx = 0; slotNdx < numSlots; slotNdx++)
    481 	{
    482 		int curLoc = location + slotNdx;
    483 
    484 		glEnableVertexAttribArray(curLoc);
    485 		glVertexAttribDivisor(curLoc, divisor);
    486 
    487 		if (isFloatCase)
    488 			glVertexAttribPointer(curLoc, typeSize, GL_FLOAT, GL_FALSE, 0, attrPtr);
    489 		else if (isIntCase)
    490 			glVertexAttribIPointer(curLoc, typeSize, GL_INT, 0, attrPtr);
    491 		else if (isUintCase)
    492 			glVertexAttribIPointer(curLoc, typeSize, GL_UNSIGNED_INT, 0, attrPtr);
    493 		else if (isMatCase)
    494 		{
    495 			int numRows = glu::getDataTypeMatrixNumRows(m_rgbAttrType);
    496 			int numCols = glu::getDataTypeMatrixNumColumns(m_rgbAttrType);
    497 
    498 			glVertexAttribPointer(curLoc, numRows, GL_FLOAT, GL_FALSE, numCols*numRows*sizeof(float), attrPtr);
    499 		}
    500 		else
    501 			DE_ASSERT(DE_FALSE);
    502 	}
    503 }
    504 
    505 void InstancedRenderingCase::setupAndRender (void)
    506 {
    507 	deUint32 program = m_program->getProgram();
    508 
    509 	glUseProgram(program);
    510 
    511 	{
    512 		// Setup attributes.
    513 
    514 		// Position attribute is non-instanced.
    515 		int positionLoc = glGetAttribLocation(program, "a_position");
    516 		glEnableVertexAttribArray(positionLoc);
    517 		glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, &m_gridVertexPositions[0]);
    518 
    519 		if (m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED)
    520 		{
    521 			if (m_instancingType == TYPE_ATTRIB_DIVISOR)
    522 			{
    523 				// Position offset attribute is instanced with separate offset for every instance.
    524 				int offsetLoc = glGetAttribLocation(program, "a_instanceOffset");
    525 				glEnableVertexAttribArray(offsetLoc);
    526 				glVertexAttribDivisor(offsetLoc, 1);
    527 				glVertexAttribPointer(offsetLoc, OFFSET_COMPONENTS, GL_FLOAT, GL_FALSE, 0, &m_instanceOffsets[0]);
    528 
    529 				int rLoc = glGetAttribLocation(program, "a_instanceR");
    530 				setupVarAttribPointer((void*)&m_instanceColorR[0].u32, rLoc, ATTRIB_DIVISOR_R);
    531 			}
    532 
    533 			int gLoc = glGetAttribLocation(program, "a_instanceG");
    534 			setupVarAttribPointer((void*)&m_instanceColorG[0].u32, gLoc, ATTRIB_DIVISOR_G);
    535 
    536 			int bLoc = glGetAttribLocation(program, "a_instanceB");
    537 			setupVarAttribPointer((void*)&m_instanceColorB[0].u32, bLoc, ATTRIB_DIVISOR_B);
    538 		}
    539 	}
    540 
    541 	// Draw using appropriate function.
    542 
    543 	if (m_function == FUNCTION_DRAW_ARRAYS_INSTANCED)
    544 	{
    545 		const int numPositionComponents = 2;
    546 		glDrawArraysInstanced(GL_TRIANGLES, 0, ((int)m_gridVertexPositions.size() / numPositionComponents), m_numInstances);
    547 	}
    548 	else
    549 		glDrawElementsInstanced(GL_TRIANGLES, (int)m_gridIndices.size(), GL_UNSIGNED_SHORT, &m_gridIndices[0], m_numInstances);
    550 
    551 	glUseProgram(0);
    552 }
    553 
    554 void InstancedRenderingCase::computeReference (tcu::Surface& dst)
    555 {
    556 	int wid = dst.getWidth();
    557 	int hei = dst.getHeight();
    558 
    559 	// Draw a rectangle (vertical bar) for each instance.
    560 
    561 	for (int instanceNdx = 0; instanceNdx < m_numInstances; instanceNdx++)
    562 	{
    563 		int xStart		= instanceNdx * wid / m_numInstances;
    564 		int xEnd		= (instanceNdx + 1) * wid / m_numInstances;
    565 
    566 		// Emulate attribute divisors if that is the case.
    567 
    568 		int clrNdxR		= m_instancingType == TYPE_ATTRIB_DIVISOR									? instanceNdx / ATTRIB_DIVISOR_R : instanceNdx;
    569 		int clrNdxG		= m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED	? instanceNdx / ATTRIB_DIVISOR_G : instanceNdx;
    570 		int clrNdxB		= m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED	? instanceNdx / ATTRIB_DIVISOR_B : instanceNdx;
    571 
    572 		int rInstances	= m_instancingType == TYPE_ATTRIB_DIVISOR									? m_numInstances / ATTRIB_DIVISOR_R + (m_numInstances % ATTRIB_DIVISOR_R == 0 ? 0 : 1) : m_numInstances;
    573 		int gInstances	= m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED	? m_numInstances / ATTRIB_DIVISOR_G + (m_numInstances % ATTRIB_DIVISOR_G == 0 ? 0 : 1) : m_numInstances;
    574 		int bInstances	= m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED	? m_numInstances / ATTRIB_DIVISOR_B + (m_numInstances % ATTRIB_DIVISOR_B == 0 ? 0 : 1) : m_numInstances;
    575 
    576 		// Calculate colors.
    577 
    578 		float r = (float)clrNdxR / (float)rInstances;
    579 		float g = (float)clrNdxG * 2.0f / (float)gInstances;
    580 		float b = 1.0f - (float)clrNdxB / (float)bInstances;
    581 
    582 		// Convert to integer and back if shader inputs are integers.
    583 
    584 		if (glu::isDataTypeIntOrIVec(m_rgbAttrType))
    585 		{
    586 			deInt32 intR = (deInt32)(r*FLOAT_INT_SCALE + FLOAT_INT_BIAS);
    587 			deInt32 intG = (deInt32)(g*FLOAT_INT_SCALE + FLOAT_INT_BIAS);
    588 			deInt32 intB = (deInt32)(b*FLOAT_INT_SCALE + FLOAT_INT_BIAS);
    589 			r = (float)(intR - FLOAT_INT_BIAS) / FLOAT_INT_SCALE;
    590 			g = (float)(intG - FLOAT_INT_BIAS) / FLOAT_INT_SCALE;
    591 			b = (float)(intB - FLOAT_INT_BIAS) / FLOAT_INT_SCALE;
    592 		}
    593 		else if(glu::isDataTypeUintOrUVec(m_rgbAttrType))
    594 		{
    595 			deUint32 uintR = (deInt32)(r*FLOAT_UINT_SCALE + FLOAT_UINT_BIAS);
    596 			deUint32 uintG = (deInt32)(g*FLOAT_UINT_SCALE + FLOAT_UINT_BIAS);
    597 			deUint32 uintB = (deInt32)(b*FLOAT_UINT_SCALE + FLOAT_UINT_BIAS);
    598 			r = (float)(uintR - FLOAT_UINT_BIAS) / FLOAT_UINT_SCALE;
    599 			g = (float)(uintG - FLOAT_UINT_BIAS) / FLOAT_UINT_SCALE;
    600 			b = (float)(uintB - FLOAT_UINT_BIAS) / FLOAT_UINT_SCALE;
    601 		}
    602 
    603 		// Draw rectangle.
    604 
    605 		for (int y = 0; y < hei; y++)
    606 			for (int x = xStart; x < xEnd; x++)
    607 				dst.setPixel(x, y, tcu::RGBA(tcu::Vec4(r, g, b, 1.0f)));
    608 	}
    609 }
    610 
    611 InstancedRenderingTests::InstancedRenderingTests (Context& context)
    612 	: TestCaseGroup(context, "instanced", "Instanced rendering tests")
    613 {
    614 }
    615 
    616 InstancedRenderingTests::~InstancedRenderingTests (void)
    617 {
    618 }
    619 
    620 void InstancedRenderingTests::init (void)
    621 {
    622 	// Cases testing function, instancing method and instance count.
    623 
    624 	static const int instanceCounts[] = { 1, 2, 4, 20 };
    625 
    626 	for (int function = 0; function < (int)InstancedRenderingCase::FUNCTION_LAST; function++)
    627 	{
    628 		const char* functionName = function == (int)InstancedRenderingCase::FUNCTION_DRAW_ARRAYS_INSTANCED		? "draw_arrays_instanced"
    629 								 : function == (int)InstancedRenderingCase::FUNCTION_DRAW_ELEMENTS_INSTANCED	? "draw_elements_instanced"
    630 								 : DE_NULL;
    631 
    632 		const char* functionDesc = function == (int)InstancedRenderingCase::FUNCTION_DRAW_ARRAYS_INSTANCED		? "Use glDrawArraysInstanced()"
    633 								 : function == (int)InstancedRenderingCase::FUNCTION_DRAW_ELEMENTS_INSTANCED	? "Use glDrawElementsInstanced()"
    634 								 : DE_NULL;
    635 
    636 		DE_ASSERT(functionName != DE_NULL);
    637 		DE_ASSERT(functionDesc != DE_NULL);
    638 
    639 		TestCaseGroup* functionGroup = new TestCaseGroup(m_context, functionName, functionDesc);
    640 		addChild(functionGroup);
    641 
    642 		for (int instancingType = 0; instancingType < (int)InstancedRenderingCase::TYPE_LAST; instancingType++)
    643 		{
    644 			const char* instancingTypeName = instancingType == (int)InstancedRenderingCase::TYPE_INSTANCE_ID	? "instance_id"
    645 										   : instancingType == (int)InstancedRenderingCase::TYPE_ATTRIB_DIVISOR	? "attribute_divisor"
    646 										   : instancingType == (int)InstancedRenderingCase::TYPE_MIXED			? "mixed"
    647 										   : DE_NULL;
    648 
    649 			const char* instancingTypeDesc = instancingType == (int)InstancedRenderingCase::TYPE_INSTANCE_ID	? "Use gl_InstanceID for instancing"
    650 										   : instancingType == (int)InstancedRenderingCase::TYPE_ATTRIB_DIVISOR	? "Use vertex attribute divisors for instancing"
    651 										   : instancingType == (int)InstancedRenderingCase::TYPE_MIXED			? "Use both gl_InstanceID and vertex attribute divisors for instancing"
    652 										   : DE_NULL;
    653 
    654 			DE_ASSERT(instancingTypeName != DE_NULL);
    655 			DE_ASSERT(instancingTypeDesc != DE_NULL);
    656 
    657 			TestCaseGroup* instancingTypeGroup = new TestCaseGroup(m_context, instancingTypeName, instancingTypeDesc);
    658 			functionGroup->addChild(instancingTypeGroup);
    659 
    660 			for (int countNdx = 0; countNdx < DE_LENGTH_OF_ARRAY(instanceCounts); countNdx++)
    661 			{
    662 				std::string countName = de::toString(instanceCounts[countNdx]) + "_instances";
    663 
    664 				instancingTypeGroup->addChild(new InstancedRenderingCase(m_context, countName.c_str(), "",
    665 																		 (InstancedRenderingCase::DrawFunction)function,
    666 																		 (InstancedRenderingCase::InstancingType)instancingType,
    667 																		 glu::TYPE_FLOAT,
    668 																		 instanceCounts[countNdx]));
    669 			}
    670 		}
    671 	}
    672 
    673 	// Data type specific cases.
    674 
    675 	static const glu::DataType s_testTypes[] =
    676 	{
    677 		glu::TYPE_FLOAT,
    678 		glu::TYPE_FLOAT_VEC2,
    679 		glu::TYPE_FLOAT_VEC3,
    680 		glu::TYPE_FLOAT_VEC4,
    681 		glu::TYPE_FLOAT_MAT2,
    682 		glu::TYPE_FLOAT_MAT2X3,
    683 		glu::TYPE_FLOAT_MAT2X4,
    684 		glu::TYPE_FLOAT_MAT3X2,
    685 		glu::TYPE_FLOAT_MAT3,
    686 		glu::TYPE_FLOAT_MAT3X4,
    687 		glu::TYPE_FLOAT_MAT4X2,
    688 		glu::TYPE_FLOAT_MAT4X3,
    689 		glu::TYPE_FLOAT_MAT4,
    690 
    691 		glu::TYPE_INT,
    692 		glu::TYPE_INT_VEC2,
    693 		glu::TYPE_INT_VEC3,
    694 		glu::TYPE_INT_VEC4,
    695 
    696 		glu::TYPE_UINT,
    697 		glu::TYPE_UINT_VEC2,
    698 		glu::TYPE_UINT_VEC3,
    699 		glu::TYPE_UINT_VEC4
    700 	};
    701 
    702 	const int typeTestNumInstances = 4;
    703 
    704 	TestCaseGroup* typesGroup = new TestCaseGroup(m_context, "types", "Tests for instanced attributes of particular data types");
    705 	addChild(typesGroup);
    706 
    707 	for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_testTypes); typeNdx++)
    708 	{
    709 		glu::DataType type = s_testTypes[typeNdx];
    710 
    711 		typesGroup->addChild(new InstancedRenderingCase(m_context, glu::getDataTypeName(type), "",
    712 														InstancedRenderingCase::FUNCTION_DRAW_ARRAYS_INSTANCED,
    713 														InstancedRenderingCase::TYPE_ATTRIB_DIVISOR,
    714 														type,
    715 														typeTestNumInstances));
    716 	}
    717 }
    718 
    719 } // Functional
    720 } // gles3
    721 } // deqp
    722