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