1e5c31af7Sopenharmony_ci/*-------------------------------------------------------------------------
2e5c31af7Sopenharmony_ci * drawElements Quality Program OpenGL ES 2.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 Shader operator performance tests.
22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
23e5c31af7Sopenharmony_ci
24e5c31af7Sopenharmony_ci#include "es2pShaderOperatorTests.hpp"
25e5c31af7Sopenharmony_ci#include "glsCalibration.hpp"
26e5c31af7Sopenharmony_ci#include "gluShaderUtil.hpp"
27e5c31af7Sopenharmony_ci#include "gluShaderProgram.hpp"
28e5c31af7Sopenharmony_ci#include "gluPixelTransfer.hpp"
29e5c31af7Sopenharmony_ci#include "tcuTestLog.hpp"
30e5c31af7Sopenharmony_ci#include "tcuRenderTarget.hpp"
31e5c31af7Sopenharmony_ci#include "tcuCommandLine.hpp"
32e5c31af7Sopenharmony_ci#include "tcuSurface.hpp"
33e5c31af7Sopenharmony_ci#include "deStringUtil.hpp"
34e5c31af7Sopenharmony_ci#include "deSharedPtr.hpp"
35e5c31af7Sopenharmony_ci#include "deClock.h"
36e5c31af7Sopenharmony_ci#include "deMath.h"
37e5c31af7Sopenharmony_ci
38e5c31af7Sopenharmony_ci#include "glwEnums.hpp"
39e5c31af7Sopenharmony_ci#include "glwFunctions.hpp"
40e5c31af7Sopenharmony_ci
41e5c31af7Sopenharmony_ci#include <map>
42e5c31af7Sopenharmony_ci#include <algorithm>
43e5c31af7Sopenharmony_ci#include <limits>
44e5c31af7Sopenharmony_ci#include <set>
45e5c31af7Sopenharmony_ci
46e5c31af7Sopenharmony_cinamespace deqp
47e5c31af7Sopenharmony_ci{
48e5c31af7Sopenharmony_cinamespace gles2
49e5c31af7Sopenharmony_ci{
50e5c31af7Sopenharmony_cinamespace Performance
51e5c31af7Sopenharmony_ci{
52e5c31af7Sopenharmony_ci
53e5c31af7Sopenharmony_ciusing namespace gls;
54e5c31af7Sopenharmony_ciusing namespace glu;
55e5c31af7Sopenharmony_ciusing tcu::Vec2;
56e5c31af7Sopenharmony_ciusing tcu::Vec4;
57e5c31af7Sopenharmony_ciusing tcu::TestLog;
58e5c31af7Sopenharmony_ciusing de::SharedPtr;
59e5c31af7Sopenharmony_ci
60e5c31af7Sopenharmony_ciusing std::string;
61e5c31af7Sopenharmony_ciusing std::vector;
62e5c31af7Sopenharmony_ci
63e5c31af7Sopenharmony_ci#define MEASUREMENT_FAIL() throw tcu::InternalError("Unable to get sensible measurements for estimation", DE_NULL, __FILE__, __LINE__)
64e5c31af7Sopenharmony_ci
65e5c31af7Sopenharmony_ci// Number of measurements in OperatorPerformanceCase for each workload size, unless specified otherwise by a command line argument.
66e5c31af7Sopenharmony_cistatic const int	DEFAULT_NUM_MEASUREMENTS_PER_WORKLOAD	= 3;
67e5c31af7Sopenharmony_ci// How many different workload sizes are used by OperatorPerformanceCase.
68e5c31af7Sopenharmony_cistatic const int	NUM_WORKLOADS							= 8;
69e5c31af7Sopenharmony_ci// Maximum workload size that can be attempted. In a sensible case, this most likely won't be reached.
70e5c31af7Sopenharmony_cistatic const int	MAX_WORKLOAD_SIZE						= 1<<29;
71e5c31af7Sopenharmony_ci
72e5c31af7Sopenharmony_ci// BinaryOpCase-specific constants for shader generation.
73e5c31af7Sopenharmony_cistatic const int	BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS	= 4;
74e5c31af7Sopenharmony_cistatic const int	BINARY_OPERATOR_CASE_SMALL_PROGRAM_UNROLL_AMOUNT	= 2;
75e5c31af7Sopenharmony_cistatic const int	BINARY_OPERATOR_CASE_BIG_PROGRAM_UNROLL_AMOUNT		= 4;
76e5c31af7Sopenharmony_ci
77e5c31af7Sopenharmony_ci// FunctionCase-specific constants for shader generation.
78e5c31af7Sopenharmony_cistatic const int	FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS			= 4;
79e5c31af7Sopenharmony_ci
80e5c31af7Sopenharmony_cistatic const char* const s_swizzles[][4] =
81e5c31af7Sopenharmony_ci{
82e5c31af7Sopenharmony_ci	{ "x", "yx", "yzx", "wzyx" },
83e5c31af7Sopenharmony_ci	{ "y", "zy", "wyz", "xwzy" },
84e5c31af7Sopenharmony_ci	{ "z", "wy", "zxy", "yzwx" },
85e5c31af7Sopenharmony_ci	{ "w", "xw", "yxw", "zyxw" }
86e5c31af7Sopenharmony_ci};
87e5c31af7Sopenharmony_ci
88e5c31af7Sopenharmony_citemplate <int N>
89e5c31af7Sopenharmony_cistatic tcu::Vector<float, N> mean (const vector<tcu::Vector<float, N> >& data)
90e5c31af7Sopenharmony_ci{
91e5c31af7Sopenharmony_ci	tcu::Vector<float, N> sum(0.0f);
92e5c31af7Sopenharmony_ci	for (int i = 0; i < (int)data.size(); i++)
93e5c31af7Sopenharmony_ci		sum += data[i];
94e5c31af7Sopenharmony_ci	return sum / tcu::Vector<float, N>((float)data.size());
95e5c31af7Sopenharmony_ci}
96e5c31af7Sopenharmony_ci
97e5c31af7Sopenharmony_cistatic void uniformNfv (const glw::Functions& gl, int n, int location, int count, const float* data)
98e5c31af7Sopenharmony_ci{
99e5c31af7Sopenharmony_ci	switch (n)
100e5c31af7Sopenharmony_ci	{
101e5c31af7Sopenharmony_ci		case 1: gl.uniform1fv(location, count, data); break;
102e5c31af7Sopenharmony_ci		case 2: gl.uniform2fv(location, count, data); break;
103e5c31af7Sopenharmony_ci		case 3: gl.uniform3fv(location, count, data); break;
104e5c31af7Sopenharmony_ci		case 4: gl.uniform4fv(location, count, data); break;
105e5c31af7Sopenharmony_ci		default: DE_ASSERT(false);
106e5c31af7Sopenharmony_ci	}
107e5c31af7Sopenharmony_ci}
108e5c31af7Sopenharmony_ci
109e5c31af7Sopenharmony_cistatic void uniformNiv (const glw::Functions& gl, int n, int location, int count, const int* data)
110e5c31af7Sopenharmony_ci{
111e5c31af7Sopenharmony_ci	switch (n)
112e5c31af7Sopenharmony_ci	{
113e5c31af7Sopenharmony_ci		case 1: gl.uniform1iv(location, count, data); break;
114e5c31af7Sopenharmony_ci		case 2: gl.uniform2iv(location, count, data); break;
115e5c31af7Sopenharmony_ci		case 3: gl.uniform3iv(location, count, data); break;
116e5c31af7Sopenharmony_ci		case 4: gl.uniform4iv(location, count, data); break;
117e5c31af7Sopenharmony_ci		default: DE_ASSERT(false);
118e5c31af7Sopenharmony_ci	}
119e5c31af7Sopenharmony_ci}
120e5c31af7Sopenharmony_ci
121e5c31af7Sopenharmony_cistatic void uniformMatrixNfv (const glw::Functions& gl, int n, int location, int count, const float* data)
122e5c31af7Sopenharmony_ci{
123e5c31af7Sopenharmony_ci	switch (n)
124e5c31af7Sopenharmony_ci	{
125e5c31af7Sopenharmony_ci		case 2: gl.uniformMatrix2fv(location, count, GL_FALSE, &data[0]); break;
126e5c31af7Sopenharmony_ci		case 3: gl.uniformMatrix3fv(location, count, GL_FALSE, &data[0]); break;
127e5c31af7Sopenharmony_ci		case 4: gl.uniformMatrix4fv(location, count, GL_FALSE, &data[0]); break;
128e5c31af7Sopenharmony_ci		default: DE_ASSERT(false);
129e5c31af7Sopenharmony_ci	}
130e5c31af7Sopenharmony_ci}
131e5c31af7Sopenharmony_ci
132e5c31af7Sopenharmony_cistatic glu::DataType getDataTypeFloatOrVec (int size)
133e5c31af7Sopenharmony_ci{
134e5c31af7Sopenharmony_ci	return size == 1 ? glu::TYPE_FLOAT : glu::getDataTypeFloatVec(size);
135e5c31af7Sopenharmony_ci}
136e5c31af7Sopenharmony_ci
137e5c31af7Sopenharmony_cistatic int getIterationCountOrDefault (const tcu::CommandLine& cmdLine, int def)
138e5c31af7Sopenharmony_ci{
139e5c31af7Sopenharmony_ci	const int cmdLineVal = cmdLine.getTestIterationCount();
140e5c31af7Sopenharmony_ci	return cmdLineVal > 0 ? cmdLineVal : def;
141e5c31af7Sopenharmony_ci}
142e5c31af7Sopenharmony_ci
143e5c31af7Sopenharmony_cistatic string lineParamsString (const LineParameters& params)
144e5c31af7Sopenharmony_ci{
145e5c31af7Sopenharmony_ci	return "y = " + de::toString(params.offset) + " + " + de::toString(params.coefficient) + "*x";
146e5c31af7Sopenharmony_ci}
147e5c31af7Sopenharmony_ci
148e5c31af7Sopenharmony_cinamespace
149e5c31af7Sopenharmony_ci{
150e5c31af7Sopenharmony_ci
151e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
152e5c31af7Sopenharmony_ci * \brief Abstract class for measuring shader operator performance.
153e5c31af7Sopenharmony_ci *
154e5c31af7Sopenharmony_ci * This class draws multiple times with different workload sizes (set
155e5c31af7Sopenharmony_ci * via a uniform, by subclass). Time for each frame is measured, and the
156e5c31af7Sopenharmony_ci * slope of the workload size vs frame time data is estimated. This slope
157e5c31af7Sopenharmony_ci * tells us the estimated increase in frame time caused by a workload
158e5c31af7Sopenharmony_ci * increase of 1 unit (what 1 workload unit means is up to subclass).
159e5c31af7Sopenharmony_ci *
160e5c31af7Sopenharmony_ci * Generally, the shaders contain not just the operation we're interested
161e5c31af7Sopenharmony_ci * in (e.g. addition) but also some other stuff (e.g. loop overhead). To
162e5c31af7Sopenharmony_ci * eliminate this cost, we actually do the stuff described in the above
163e5c31af7Sopenharmony_ci * paragraph with multiple programs (usually two), which contain different
164e5c31af7Sopenharmony_ci * kinds of workload (e.g. different loop contents). Then we can (in
165e5c31af7Sopenharmony_ci * theory) compute the cost of just one operation in a subclass-dependent
166e5c31af7Sopenharmony_ci * manner.
167e5c31af7Sopenharmony_ci *
168e5c31af7Sopenharmony_ci * At this point, the result tells us the increase in frame time caused
169e5c31af7Sopenharmony_ci * by the addition of one operation. Dividing this by the amount of
170e5c31af7Sopenharmony_ci * draw calls in a frame, and further by the amount of vertices or
171e5c31af7Sopenharmony_ci * fragments in a draw call, we get the time cost of one operation.
172e5c31af7Sopenharmony_ci *
173e5c31af7Sopenharmony_ci * In reality, there sometimes isn't just a trivial linear dependence
174e5c31af7Sopenharmony_ci * between workload size and frame time. Instead, there tends to be some
175e5c31af7Sopenharmony_ci * amount of initial "free" operations. That is, it may be that all
176e5c31af7Sopenharmony_ci * workload sizes below some positive integer C yield the same frame time,
177e5c31af7Sopenharmony_ci * and only workload sizes beyond C increase the frame time in a supposedly
178e5c31af7Sopenharmony_ci * linear manner. Graphically, this means that there graph consists of two
179e5c31af7Sopenharmony_ci * parts: a horizontal left part, and a linearly increasing right part; the
180e5c31af7Sopenharmony_ci * right part starts where the left parts ends. The principal task of these
181e5c31af7Sopenharmony_ci * tests is to look at the slope of the increasing right part. Additionally
182e5c31af7Sopenharmony_ci * an estimate for the amount of initial free operations is calculated.
183e5c31af7Sopenharmony_ci * Note that it is also normal to get graphs where the horizontal left part
184e5c31af7Sopenharmony_ci * is of zero width, i.e. there are no free operations.
185e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
186e5c31af7Sopenharmony_ciclass OperatorPerformanceCase : public tcu::TestCase
187e5c31af7Sopenharmony_ci{
188e5c31af7Sopenharmony_cipublic:
189e5c31af7Sopenharmony_ci	enum CaseType
190e5c31af7Sopenharmony_ci	{
191e5c31af7Sopenharmony_ci		CASETYPE_VERTEX = 0,
192e5c31af7Sopenharmony_ci		CASETYPE_FRAGMENT,
193e5c31af7Sopenharmony_ci
194e5c31af7Sopenharmony_ci		CASETYPE_LAST
195e5c31af7Sopenharmony_ci	};
196e5c31af7Sopenharmony_ci
197e5c31af7Sopenharmony_ci	struct InitialCalibration
198e5c31af7Sopenharmony_ci	{
199e5c31af7Sopenharmony_ci		int initialNumCalls;
200e5c31af7Sopenharmony_ci		InitialCalibration (void) : initialNumCalls(1) {}
201e5c31af7Sopenharmony_ci	};
202e5c31af7Sopenharmony_ci
203e5c31af7Sopenharmony_ci	typedef SharedPtr<InitialCalibration> InitialCalibrationStorage;
204e5c31af7Sopenharmony_ci
205e5c31af7Sopenharmony_ci								OperatorPerformanceCase		(tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description,
206e5c31af7Sopenharmony_ci															 CaseType caseType, int numWorkloads, const InitialCalibrationStorage& initialCalibrationStorage);
207e5c31af7Sopenharmony_ci								~OperatorPerformanceCase	(void);
208e5c31af7Sopenharmony_ci
209e5c31af7Sopenharmony_ci	void						init						(void);
210e5c31af7Sopenharmony_ci	void						deinit						(void);
211e5c31af7Sopenharmony_ci
212e5c31af7Sopenharmony_ci	IterateResult				iterate						(void);
213e5c31af7Sopenharmony_ci
214e5c31af7Sopenharmony_ci	struct AttribSpec
215e5c31af7Sopenharmony_ci	{
216e5c31af7Sopenharmony_ci		AttribSpec (const char* name_, const tcu::Vec4& p00_, const tcu::Vec4& p01_, const tcu::Vec4& p10_, const tcu::Vec4& p11_)
217e5c31af7Sopenharmony_ci			: name		(name_)
218e5c31af7Sopenharmony_ci			, p00		(p00_)
219e5c31af7Sopenharmony_ci			, p01		(p01_)
220e5c31af7Sopenharmony_ci			, p10		(p10_)
221e5c31af7Sopenharmony_ci			, p11		(p11_)
222e5c31af7Sopenharmony_ci		{
223e5c31af7Sopenharmony_ci		}
224e5c31af7Sopenharmony_ci
225e5c31af7Sopenharmony_ci		AttribSpec (void) {}
226e5c31af7Sopenharmony_ci
227e5c31af7Sopenharmony_ci		std::string		name;
228e5c31af7Sopenharmony_ci		tcu::Vec4		p00;	//!< Bottom left.
229e5c31af7Sopenharmony_ci		tcu::Vec4		p01;	//!< Bottom right.
230e5c31af7Sopenharmony_ci		tcu::Vec4		p10;	//!< Top left.
231e5c31af7Sopenharmony_ci		tcu::Vec4		p11;	//!< Top right.
232e5c31af7Sopenharmony_ci	};
233e5c31af7Sopenharmony_ci
234e5c31af7Sopenharmony_ciprotected:
235e5c31af7Sopenharmony_ci	struct ProgramContext
236e5c31af7Sopenharmony_ci	{
237e5c31af7Sopenharmony_ci		string				vertShaderSource;
238e5c31af7Sopenharmony_ci		string				fragShaderSource;
239e5c31af7Sopenharmony_ci		vector<AttribSpec>	attributes;
240e5c31af7Sopenharmony_ci
241e5c31af7Sopenharmony_ci		string				description;
242e5c31af7Sopenharmony_ci
243e5c31af7Sopenharmony_ci		ProgramContext (void) {}
244e5c31af7Sopenharmony_ci		ProgramContext (const string& vs, const string& fs, const vector<AttribSpec>& attrs, const string& desc)
245e5c31af7Sopenharmony_ci			: vertShaderSource(vs), fragShaderSource(fs), attributes(attrs), description(desc) {}
246e5c31af7Sopenharmony_ci	};
247e5c31af7Sopenharmony_ci
248e5c31af7Sopenharmony_ci	virtual vector<ProgramContext>	generateProgramData					(void) const = 0;
249e5c31af7Sopenharmony_ci	//! Sets program-specific uniforms that don't depend on the workload size.
250e5c31af7Sopenharmony_ci	virtual void					setGeneralUniforms					(deUint32 program) const = 0;
251e5c31af7Sopenharmony_ci	//! Sets the uniform(s) that specifies the workload size in the shader.
252e5c31af7Sopenharmony_ci	virtual void					setWorkloadSizeUniform				(deUint32 program, int workload) const = 0;
253e5c31af7Sopenharmony_ci	//! Computes the cost of a single operation, given the workload costs per program.
254e5c31af7Sopenharmony_ci	virtual float					computeSingleOperationTime			(const vector<float>& perProgramWorkloadCosts) const = 0;
255e5c31af7Sopenharmony_ci	//! Logs a human-readable description of what computeSingleOperationTime does.
256e5c31af7Sopenharmony_ci	virtual void					logSingleOperationCalculationInfo	(void) const = 0;
257e5c31af7Sopenharmony_ci
258e5c31af7Sopenharmony_ci	glu::RenderContext&				m_renderCtx;
259e5c31af7Sopenharmony_ci
260e5c31af7Sopenharmony_ci	CaseType						m_caseType;
261e5c31af7Sopenharmony_ci
262e5c31af7Sopenharmony_ciprivate:
263e5c31af7Sopenharmony_ci	enum State
264e5c31af7Sopenharmony_ci	{
265e5c31af7Sopenharmony_ci		STATE_CALIBRATING = 0,		//!< Calibrate draw call count, using first program in m_programs, with workload size 1.
266e5c31af7Sopenharmony_ci		STATE_FIND_HIGH_WORKLOAD,	//!< Find an appropriate lower bound for the highest workload size we intend to use (one with high-enough frame time compared to workload size 1) for each program.
267e5c31af7Sopenharmony_ci		STATE_MEASURING,			//!< Do actual measurements, for each program in m_programs.
268e5c31af7Sopenharmony_ci		STATE_REPORTING,			//!< Measurements are done; calculate results and log.
269e5c31af7Sopenharmony_ci		STATE_FINISHED,				//!< All done.
270e5c31af7Sopenharmony_ci
271e5c31af7Sopenharmony_ci		STATE_LAST
272e5c31af7Sopenharmony_ci	};
273e5c31af7Sopenharmony_ci
274e5c31af7Sopenharmony_ci	struct WorkloadRecord
275e5c31af7Sopenharmony_ci	{
276e5c31af7Sopenharmony_ci		int				workloadSize;
277e5c31af7Sopenharmony_ci		vector<float>	frameTimes; //!< In microseconds.
278e5c31af7Sopenharmony_ci
279e5c31af7Sopenharmony_ci				WorkloadRecord	(int workloadSize_)						: workloadSize(workloadSize_) {}
280e5c31af7Sopenharmony_ci		bool	operator<		(const WorkloadRecord& other) const		{ return this->workloadSize < other.workloadSize; }
281e5c31af7Sopenharmony_ci		void	addFrameTime	(float time)							{ frameTimes.push_back(time); }
282e5c31af7Sopenharmony_ci		float	getMedianTime	(void) const
283e5c31af7Sopenharmony_ci		{
284e5c31af7Sopenharmony_ci			vector<float> times = frameTimes;
285e5c31af7Sopenharmony_ci			std::sort(times.begin(), times.end());
286e5c31af7Sopenharmony_ci			return times.size() % 2 == 0 ?
287e5c31af7Sopenharmony_ci					(times[times.size()/2-1] + times[times.size()/2])*0.5f :
288e5c31af7Sopenharmony_ci					times[times.size()/2];
289e5c31af7Sopenharmony_ci		}
290e5c31af7Sopenharmony_ci	};
291e5c31af7Sopenharmony_ci
292e5c31af7Sopenharmony_ci	void								prepareProgram				(int progNdx);					//!< Sets attributes and uniforms for m_programs[progNdx].
293e5c31af7Sopenharmony_ci	void								prepareWorkload				(int progNdx, int workload);	//!< Calls setWorkloadSizeUniform and draws, in case the implementation does some draw-time compilation.
294e5c31af7Sopenharmony_ci	void								prepareNextRound			(void);							//!< Increases workload and/or updates m_state.
295e5c31af7Sopenharmony_ci	void								render						(int numDrawCalls);
296e5c31af7Sopenharmony_ci	deUint64							renderAndMeasure			(int numDrawCalls);
297e5c31af7Sopenharmony_ci	void								adjustAndLogGridAndViewport	(void);							//!< Log grid and viewport sizes, after possibly reducing them to reduce draw time.
298e5c31af7Sopenharmony_ci
299e5c31af7Sopenharmony_ci	vector<Vec2>						getWorkloadMedianDataPoints	(int progNdx) const; //!< [ Vec2(r.workloadSize, r.getMedianTime()) for r in m_workloadRecords[progNdx] ]
300e5c31af7Sopenharmony_ci
301e5c31af7Sopenharmony_ci	const int							m_numMeasurementsPerWorkload;
302e5c31af7Sopenharmony_ci	const int							m_numWorkloads;				//!< How many different workload sizes are used for measurement for each program.
303e5c31af7Sopenharmony_ci
304e5c31af7Sopenharmony_ci	int									m_workloadNdx;				//!< Runs from 0 to m_numWorkloads-1.
305e5c31af7Sopenharmony_ci
306e5c31af7Sopenharmony_ci	int									m_workloadMeasurementNdx;
307e5c31af7Sopenharmony_ci	vector<vector<WorkloadRecord> >		m_workloadRecordsFindHigh;	//!< The measurements done during STATE_FIND_HIGH_WORKLOAD.
308e5c31af7Sopenharmony_ci	vector<vector<WorkloadRecord> >		m_workloadRecords;			//!< The measurements of each program in m_programs. Generated during STATE_MEASURING, into index specified by m_measureProgramNdx.
309e5c31af7Sopenharmony_ci
310e5c31af7Sopenharmony_ci	State								m_state;
311e5c31af7Sopenharmony_ci	int									m_measureProgramNdx;		//!< When m_state is STATE_FIND_HIGH_WORKLOAD or STATE_MEASURING, this tells which program in m_programs is being measured.
312e5c31af7Sopenharmony_ci
313e5c31af7Sopenharmony_ci	vector<int>							m_highWorkloadSizes;		//!< The first workload size encountered during STATE_FIND_HIGH_WORKLOAD that was determined suitable, for each program.
314e5c31af7Sopenharmony_ci
315e5c31af7Sopenharmony_ci	TheilSenCalibrator					m_calibrator;
316e5c31af7Sopenharmony_ci	InitialCalibrationStorage			m_initialCalibrationStorage;
317e5c31af7Sopenharmony_ci
318e5c31af7Sopenharmony_ci	int									m_viewportWidth;
319e5c31af7Sopenharmony_ci	int									m_viewportHeight;
320e5c31af7Sopenharmony_ci	int									m_gridSizeX;
321e5c31af7Sopenharmony_ci	int									m_gridSizeY;
322e5c31af7Sopenharmony_ci
323e5c31af7Sopenharmony_ci	vector<ProgramContext>				m_programData;
324e5c31af7Sopenharmony_ci	vector<SharedPtr<ShaderProgram> >	m_programs;
325e5c31af7Sopenharmony_ci
326e5c31af7Sopenharmony_ci	std::vector<deUint32>				m_attribBuffers;
327e5c31af7Sopenharmony_ci};
328e5c31af7Sopenharmony_ci
329e5c31af7Sopenharmony_cistatic inline float triangleInterpolate (float v0, float v1, float v2, float x, float y)
330e5c31af7Sopenharmony_ci{
331e5c31af7Sopenharmony_ci	return v0 + (v2-v0)*x + (v1-v0)*y;
332e5c31af7Sopenharmony_ci}
333e5c31af7Sopenharmony_ci
334e5c31af7Sopenharmony_cistatic inline float triQuadInterpolate (float x, float y, const tcu::Vec4& quad)
335e5c31af7Sopenharmony_ci{
336e5c31af7Sopenharmony_ci	// \note Top left fill rule.
337e5c31af7Sopenharmony_ci	if (x + y < 1.0f)
338e5c31af7Sopenharmony_ci		return triangleInterpolate(quad.x(), quad.y(), quad.z(), x, y);
339e5c31af7Sopenharmony_ci	else
340e5c31af7Sopenharmony_ci		return triangleInterpolate(quad.w(), quad.z(), quad.y(), 1.0f-x, 1.0f-y);
341e5c31af7Sopenharmony_ci}
342e5c31af7Sopenharmony_ci
343e5c31af7Sopenharmony_cistatic inline int getNumVertices (int gridSizeX, int gridSizeY)
344e5c31af7Sopenharmony_ci{
345e5c31af7Sopenharmony_ci	return gridSizeX * gridSizeY * 2 * 3;
346e5c31af7Sopenharmony_ci}
347e5c31af7Sopenharmony_ci
348e5c31af7Sopenharmony_cistatic void generateVertices (std::vector<float>& dst, int gridSizeX, int gridSizeY, const OperatorPerformanceCase::AttribSpec& spec)
349e5c31af7Sopenharmony_ci{
350e5c31af7Sopenharmony_ci	const int numComponents = 4;
351e5c31af7Sopenharmony_ci
352e5c31af7Sopenharmony_ci	DE_ASSERT(gridSizeX >= 1 && gridSizeY >= 1);
353e5c31af7Sopenharmony_ci	dst.resize(getNumVertices(gridSizeX, gridSizeY) * numComponents);
354e5c31af7Sopenharmony_ci
355e5c31af7Sopenharmony_ci	{
356e5c31af7Sopenharmony_ci		int dstNdx = 0;
357e5c31af7Sopenharmony_ci
358e5c31af7Sopenharmony_ci		for (int baseY = 0; baseY < gridSizeY; baseY++)
359e5c31af7Sopenharmony_ci		for (int baseX = 0; baseX < gridSizeX; baseX++)
360e5c31af7Sopenharmony_ci		{
361e5c31af7Sopenharmony_ci			const float xf0 = (float)(baseX + 0) / (float)gridSizeX;
362e5c31af7Sopenharmony_ci			const float yf0 = (float)(baseY + 0) / (float)gridSizeY;
363e5c31af7Sopenharmony_ci			const float xf1 = (float)(baseX + 1) / (float)gridSizeX;
364e5c31af7Sopenharmony_ci			const float yf1 = (float)(baseY + 1) / (float)gridSizeY;
365e5c31af7Sopenharmony_ci
366e5c31af7Sopenharmony_ci#define ADD_VERTEX(XF, YF)										\
367e5c31af7Sopenharmony_ci	for (int compNdx = 0; compNdx < numComponents; compNdx++)	\
368e5c31af7Sopenharmony_ci		dst[dstNdx++] = triQuadInterpolate((XF), (YF), tcu::Vec4(spec.p00[compNdx], spec.p01[compNdx], spec.p10[compNdx], spec.p11[compNdx]))
369e5c31af7Sopenharmony_ci
370e5c31af7Sopenharmony_ci			ADD_VERTEX(xf0, yf0);
371e5c31af7Sopenharmony_ci			ADD_VERTEX(xf1, yf0);
372e5c31af7Sopenharmony_ci			ADD_VERTEX(xf0, yf1);
373e5c31af7Sopenharmony_ci
374e5c31af7Sopenharmony_ci			ADD_VERTEX(xf1, yf0);
375e5c31af7Sopenharmony_ci			ADD_VERTEX(xf1, yf1);
376e5c31af7Sopenharmony_ci			ADD_VERTEX(xf0, yf1);
377e5c31af7Sopenharmony_ci
378e5c31af7Sopenharmony_ci#undef ADD_VERTEX
379e5c31af7Sopenharmony_ci		}
380e5c31af7Sopenharmony_ci	}
381e5c31af7Sopenharmony_ci}
382e5c31af7Sopenharmony_ci
383e5c31af7Sopenharmony_cistatic float intersectionX (const gls::LineParameters& a, const gls::LineParameters& b)
384e5c31af7Sopenharmony_ci{
385e5c31af7Sopenharmony_ci	return (a.offset - b.offset) / (b.coefficient - a.coefficient);
386e5c31af7Sopenharmony_ci}
387e5c31af7Sopenharmony_ci
388e5c31af7Sopenharmony_cistatic int numDistinctX (const vector<Vec2>& data)
389e5c31af7Sopenharmony_ci{
390e5c31af7Sopenharmony_ci	std::set<float> xs;
391e5c31af7Sopenharmony_ci	for (int i = 0; i < (int)data.size(); i++)
392e5c31af7Sopenharmony_ci		xs.insert(data[i].x());
393e5c31af7Sopenharmony_ci	return (int)xs.size();
394e5c31af7Sopenharmony_ci}
395e5c31af7Sopenharmony_ci
396e5c31af7Sopenharmony_cistatic gls::LineParameters simpleLinearRegression (const vector<Vec2>& data)
397e5c31af7Sopenharmony_ci{
398e5c31af7Sopenharmony_ci	const Vec2	mid					= mean(data);
399e5c31af7Sopenharmony_ci
400e5c31af7Sopenharmony_ci	float		slopeNumerator		= 0.0f;
401e5c31af7Sopenharmony_ci	float		slopeDenominator	= 0.0f;
402e5c31af7Sopenharmony_ci
403e5c31af7Sopenharmony_ci	for (int i = 0; i < (int)data.size(); i++)
404e5c31af7Sopenharmony_ci	{
405e5c31af7Sopenharmony_ci		const Vec2 diff = data[i] - mid;
406e5c31af7Sopenharmony_ci
407e5c31af7Sopenharmony_ci		slopeNumerator		+= diff.x()*diff.y();
408e5c31af7Sopenharmony_ci		slopeDenominator	+= diff.x()*diff.x();
409e5c31af7Sopenharmony_ci	}
410e5c31af7Sopenharmony_ci
411e5c31af7Sopenharmony_ci	const float slope	= slopeNumerator / slopeDenominator;
412e5c31af7Sopenharmony_ci	const float offset	= mid.y() - slope*mid.x();
413e5c31af7Sopenharmony_ci
414e5c31af7Sopenharmony_ci	return gls::LineParameters(offset, slope);
415e5c31af7Sopenharmony_ci}
416e5c31af7Sopenharmony_ci
417e5c31af7Sopenharmony_cistatic float simpleLinearRegressionError (const vector<Vec2>& data)
418e5c31af7Sopenharmony_ci{
419e5c31af7Sopenharmony_ci	if (numDistinctX(data) <= 2)
420e5c31af7Sopenharmony_ci		return 0.0f;
421e5c31af7Sopenharmony_ci	else
422e5c31af7Sopenharmony_ci	{
423e5c31af7Sopenharmony_ci		const gls::LineParameters	estimator	= simpleLinearRegression(data);
424e5c31af7Sopenharmony_ci		float						error		= 0.0f;
425e5c31af7Sopenharmony_ci
426e5c31af7Sopenharmony_ci		for (int i = 0; i < (int)data.size(); i++)
427e5c31af7Sopenharmony_ci		{
428e5c31af7Sopenharmony_ci			const float estY = estimator.offset + estimator.coefficient*data[i].x();
429e5c31af7Sopenharmony_ci			const float diff = estY - data[i].y();
430e5c31af7Sopenharmony_ci			error += diff*diff;
431e5c31af7Sopenharmony_ci		}
432e5c31af7Sopenharmony_ci
433e5c31af7Sopenharmony_ci		return error / (float)data.size();
434e5c31af7Sopenharmony_ci	}
435e5c31af7Sopenharmony_ci}
436e5c31af7Sopenharmony_ci
437e5c31af7Sopenharmony_cistatic float verticalVariance (const vector<Vec2>& data)
438e5c31af7Sopenharmony_ci{
439e5c31af7Sopenharmony_ci	if (numDistinctX(data) <= 2)
440e5c31af7Sopenharmony_ci		return 0.0f;
441e5c31af7Sopenharmony_ci	else
442e5c31af7Sopenharmony_ci	{
443e5c31af7Sopenharmony_ci		const float		meanY = mean(data).y();
444e5c31af7Sopenharmony_ci		float			error = 0.0f;
445e5c31af7Sopenharmony_ci
446e5c31af7Sopenharmony_ci		for (int i = 0; i < (int)data.size(); i++)
447e5c31af7Sopenharmony_ci		{
448e5c31af7Sopenharmony_ci			const float diff = meanY - data[i].y();
449e5c31af7Sopenharmony_ci			error += diff*diff;
450e5c31af7Sopenharmony_ci		}
451e5c31af7Sopenharmony_ci
452e5c31af7Sopenharmony_ci		return error / (float)data.size();
453e5c31af7Sopenharmony_ci	}
454e5c31af7Sopenharmony_ci}
455e5c31af7Sopenharmony_ci
456e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
457e5c31af7Sopenharmony_ci * \brief Find the x coord that divides the input data into two slopes.
458e5c31af7Sopenharmony_ci *
459e5c31af7Sopenharmony_ci * The operator performance measurements tend to produce results where
460e5c31af7Sopenharmony_ci * we get small operation counts "for free" (e.g. because the operations
461e5c31af7Sopenharmony_ci * are performed during some memory transfer overhead or something),
462e5c31af7Sopenharmony_ci * resulting in a curve with two parts: an initial horizontal line segment,
463e5c31af7Sopenharmony_ci * and a rising line.
464e5c31af7Sopenharmony_ci *
465e5c31af7Sopenharmony_ci * This function finds the x coordinate that divides the input data into
466e5c31af7Sopenharmony_ci * two parts such that the sum of the mean square errors for the
467e5c31af7Sopenharmony_ci * least-squares estimated lines for the two parts is minimized, under the
468e5c31af7Sopenharmony_ci * additional condition that the left line is horizontal.
469e5c31af7Sopenharmony_ci *
470e5c31af7Sopenharmony_ci * This function returns a number X s.t. { pt | pt is in data, pt.x >= X }
471e5c31af7Sopenharmony_ci * is the right line, and the rest of data is the left line.
472e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
473e5c31af7Sopenharmony_cistatic float findSlopePivotX (const vector<Vec2>& data)
474e5c31af7Sopenharmony_ci{
475e5c31af7Sopenharmony_ci	std::set<float> xCoords;
476e5c31af7Sopenharmony_ci	for (int i = 0; i < (int)data.size(); i++)
477e5c31af7Sopenharmony_ci		xCoords.insert(data[i].x());
478e5c31af7Sopenharmony_ci
479e5c31af7Sopenharmony_ci	float			lowestError		= std::numeric_limits<float>::infinity();
480e5c31af7Sopenharmony_ci	float			bestPivotX		= -std::numeric_limits<float>::infinity();
481e5c31af7Sopenharmony_ci
482e5c31af7Sopenharmony_ci	for (std::set<float>::const_iterator pivotX = xCoords.begin(); pivotX != xCoords.end(); ++pivotX)
483e5c31af7Sopenharmony_ci	{
484e5c31af7Sopenharmony_ci		vector<Vec2> leftData;
485e5c31af7Sopenharmony_ci		vector<Vec2> rightData;
486e5c31af7Sopenharmony_ci		for (int i = 0; i < (int)data.size(); i++)
487e5c31af7Sopenharmony_ci		{
488e5c31af7Sopenharmony_ci			if (data[i].x() < *pivotX)
489e5c31af7Sopenharmony_ci				leftData.push_back(data[i]);
490e5c31af7Sopenharmony_ci			else
491e5c31af7Sopenharmony_ci				rightData.push_back(data[i]);
492e5c31af7Sopenharmony_ci		}
493e5c31af7Sopenharmony_ci
494e5c31af7Sopenharmony_ci		if (numDistinctX(rightData) < 3) // We don't trust the right data if there's too little of it.
495e5c31af7Sopenharmony_ci			break;
496e5c31af7Sopenharmony_ci
497e5c31af7Sopenharmony_ci		{
498e5c31af7Sopenharmony_ci			const float totalError = verticalVariance(leftData) + simpleLinearRegressionError(rightData);
499e5c31af7Sopenharmony_ci
500e5c31af7Sopenharmony_ci			if (totalError < lowestError)
501e5c31af7Sopenharmony_ci			{
502e5c31af7Sopenharmony_ci				lowestError = totalError;
503e5c31af7Sopenharmony_ci				bestPivotX = *pivotX;
504e5c31af7Sopenharmony_ci			}
505e5c31af7Sopenharmony_ci		}
506e5c31af7Sopenharmony_ci	}
507e5c31af7Sopenharmony_ci
508e5c31af7Sopenharmony_ci	DE_ASSERT(lowestError < std::numeric_limits<float>::infinity());
509e5c31af7Sopenharmony_ci
510e5c31af7Sopenharmony_ci	return bestPivotX;
511e5c31af7Sopenharmony_ci}
512e5c31af7Sopenharmony_ci
513e5c31af7Sopenharmony_cistruct SegmentedEstimator
514e5c31af7Sopenharmony_ci{
515e5c31af7Sopenharmony_ci	float					pivotX; //!< Value returned by findSlopePivotX, or -infinity if only single line.
516e5c31af7Sopenharmony_ci	gls::LineParameters		left;
517e5c31af7Sopenharmony_ci	gls::LineParameters		right;
518e5c31af7Sopenharmony_ci	SegmentedEstimator (const gls::LineParameters& l, const gls::LineParameters& r, float pivotX_) : pivotX(pivotX_), left(l), right(r) {}
519e5c31af7Sopenharmony_ci};
520e5c31af7Sopenharmony_ci
521e5c31af7Sopenharmony_ci/*--------------------------------------------------------------------*//*!
522e5c31af7Sopenharmony_ci * \brief Compute line estimators for (potentially) two-segment data.
523e5c31af7Sopenharmony_ci *
524e5c31af7Sopenharmony_ci * Splits the given data into left and right parts (using findSlopePivotX)
525e5c31af7Sopenharmony_ci * and returns the line estimates for them.
526e5c31af7Sopenharmony_ci *
527e5c31af7Sopenharmony_ci * Sometimes, however (especially in fragment shader cases) the data is
528e5c31af7Sopenharmony_ci * in fact not segmented, but a straight line. This function attempts to
529e5c31af7Sopenharmony_ci * detect if this the case, and if so, sets left.offset = right.offset and
530e5c31af7Sopenharmony_ci * left.slope = 0, meaning essentially that the initial "flat" part of the
531e5c31af7Sopenharmony_ci * data has zero width.
532e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/
533e5c31af7Sopenharmony_cistatic SegmentedEstimator computeSegmentedEstimator (const vector<Vec2>& data)
534e5c31af7Sopenharmony_ci{
535e5c31af7Sopenharmony_ci	const float		pivotX = findSlopePivotX(data);
536e5c31af7Sopenharmony_ci	vector<Vec2>	leftData;
537e5c31af7Sopenharmony_ci	vector<Vec2>	rightData;
538e5c31af7Sopenharmony_ci
539e5c31af7Sopenharmony_ci	for (int i = 0; i < (int)data.size(); i++)
540e5c31af7Sopenharmony_ci	{
541e5c31af7Sopenharmony_ci		if (data[i].x() < pivotX)
542e5c31af7Sopenharmony_ci			leftData.push_back(data[i]);
543e5c31af7Sopenharmony_ci		else
544e5c31af7Sopenharmony_ci			rightData.push_back(data[i]);
545e5c31af7Sopenharmony_ci	}
546e5c31af7Sopenharmony_ci
547e5c31af7Sopenharmony_ci	{
548e5c31af7Sopenharmony_ci		const gls::LineParameters leftLine		= gls::theilSenLinearRegression(leftData);
549e5c31af7Sopenharmony_ci		const gls::LineParameters rightLine		= gls::theilSenLinearRegression(rightData);
550e5c31af7Sopenharmony_ci
551e5c31af7Sopenharmony_ci		if (numDistinctX(leftData) < 2 || leftLine.coefficient > rightLine.coefficient*0.5f)
552e5c31af7Sopenharmony_ci		{
553e5c31af7Sopenharmony_ci			// Left data doesn't seem credible; assume the data is just a single line.
554e5c31af7Sopenharmony_ci			const gls::LineParameters entireLine = gls::theilSenLinearRegression(data);
555e5c31af7Sopenharmony_ci			return SegmentedEstimator(gls::LineParameters(entireLine.offset, 0.0f), entireLine, -std::numeric_limits<float>::infinity());
556e5c31af7Sopenharmony_ci		}
557e5c31af7Sopenharmony_ci		else
558e5c31af7Sopenharmony_ci			return SegmentedEstimator(leftLine, rightLine, pivotX);
559e5c31af7Sopenharmony_ci	}
560e5c31af7Sopenharmony_ci}
561e5c31af7Sopenharmony_ci
562e5c31af7Sopenharmony_ciOperatorPerformanceCase::OperatorPerformanceCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description,
563e5c31af7Sopenharmony_ci												  CaseType caseType, int numWorkloads, const InitialCalibrationStorage& initialCalibrationStorage)
564e5c31af7Sopenharmony_ci	: tcu::TestCase					(testCtx, tcu::NODETYPE_PERFORMANCE, name, description)
565e5c31af7Sopenharmony_ci	, m_renderCtx					(renderCtx)
566e5c31af7Sopenharmony_ci	, m_caseType					(caseType)
567e5c31af7Sopenharmony_ci	, m_numMeasurementsPerWorkload	(getIterationCountOrDefault(m_testCtx.getCommandLine(), DEFAULT_NUM_MEASUREMENTS_PER_WORKLOAD))
568e5c31af7Sopenharmony_ci	, m_numWorkloads				(numWorkloads)
569e5c31af7Sopenharmony_ci	, m_workloadNdx					(-1)
570e5c31af7Sopenharmony_ci	, m_workloadMeasurementNdx		(-1)
571e5c31af7Sopenharmony_ci	, m_state						(STATE_LAST)
572e5c31af7Sopenharmony_ci	, m_measureProgramNdx			(-1)
573e5c31af7Sopenharmony_ci	, m_initialCalibrationStorage	(initialCalibrationStorage)
574e5c31af7Sopenharmony_ci	, m_viewportWidth				(caseType == CASETYPE_VERTEX	? 32	: renderCtx.getRenderTarget().getWidth())
575e5c31af7Sopenharmony_ci	, m_viewportHeight				(caseType == CASETYPE_VERTEX	? 32	: renderCtx.getRenderTarget().getHeight())
576e5c31af7Sopenharmony_ci	, m_gridSizeX					(caseType == CASETYPE_FRAGMENT	? 1		: 100)
577e5c31af7Sopenharmony_ci	, m_gridSizeY					(caseType == CASETYPE_FRAGMENT	? 1		: 100)
578e5c31af7Sopenharmony_ci{
579e5c31af7Sopenharmony_ci	DE_ASSERT(m_numWorkloads > 0);
580e5c31af7Sopenharmony_ci}
581e5c31af7Sopenharmony_ci
582e5c31af7Sopenharmony_ciOperatorPerformanceCase::~OperatorPerformanceCase (void)
583e5c31af7Sopenharmony_ci{
584e5c31af7Sopenharmony_ci	if (!m_attribBuffers.empty())
585e5c31af7Sopenharmony_ci	{
586e5c31af7Sopenharmony_ci		m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_attribBuffers.size(), &m_attribBuffers[0]);
587e5c31af7Sopenharmony_ci		m_attribBuffers.clear();
588e5c31af7Sopenharmony_ci	}
589e5c31af7Sopenharmony_ci}
590e5c31af7Sopenharmony_ci
591e5c31af7Sopenharmony_cistatic void logRenderTargetInfo (TestLog& log, const tcu::RenderTarget& renderTarget)
592e5c31af7Sopenharmony_ci{
593e5c31af7Sopenharmony_ci	log << TestLog::Section("RenderTarget", "Render target")
594e5c31af7Sopenharmony_ci		<< TestLog::Message << "size: " << renderTarget.getWidth() << "x" << renderTarget.getHeight() << TestLog::EndMessage
595e5c31af7Sopenharmony_ci		<< TestLog::Message << "bits:"
596e5c31af7Sopenharmony_ci							<< " R" << renderTarget.getPixelFormat().redBits
597e5c31af7Sopenharmony_ci							<< " G" << renderTarget.getPixelFormat().greenBits
598e5c31af7Sopenharmony_ci							<< " B" << renderTarget.getPixelFormat().blueBits
599e5c31af7Sopenharmony_ci							<< " A" << renderTarget.getPixelFormat().alphaBits
600e5c31af7Sopenharmony_ci							<< " D" << renderTarget.getDepthBits()
601e5c31af7Sopenharmony_ci							<< " S" << renderTarget.getStencilBits()
602e5c31af7Sopenharmony_ci							<< TestLog::EndMessage;
603e5c31af7Sopenharmony_ci
604e5c31af7Sopenharmony_ci	if (renderTarget.getNumSamples() != 0)
605e5c31af7Sopenharmony_ci		log << TestLog::Message << renderTarget.getNumSamples() << "x MSAA" << TestLog::EndMessage;
606e5c31af7Sopenharmony_ci	else
607e5c31af7Sopenharmony_ci		log << TestLog::Message << "No MSAA" << TestLog::EndMessage;
608e5c31af7Sopenharmony_ci
609e5c31af7Sopenharmony_ci	log << TestLog::EndSection;
610e5c31af7Sopenharmony_ci}
611e5c31af7Sopenharmony_ci
612e5c31af7Sopenharmony_civector<Vec2> OperatorPerformanceCase::getWorkloadMedianDataPoints (int progNdx) const
613e5c31af7Sopenharmony_ci{
614e5c31af7Sopenharmony_ci	const vector<WorkloadRecord>&	records = m_workloadRecords[progNdx];
615e5c31af7Sopenharmony_ci	vector<Vec2>					result;
616e5c31af7Sopenharmony_ci
617e5c31af7Sopenharmony_ci	for (int i = 0; i < (int)records.size(); i++)
618e5c31af7Sopenharmony_ci		result.push_back(Vec2((float)records[i].workloadSize, records[i].getMedianTime()));
619e5c31af7Sopenharmony_ci
620e5c31af7Sopenharmony_ci	return result;
621e5c31af7Sopenharmony_ci}
622e5c31af7Sopenharmony_ci
623e5c31af7Sopenharmony_civoid OperatorPerformanceCase::prepareProgram (int progNdx)
624e5c31af7Sopenharmony_ci{
625e5c31af7Sopenharmony_ci	DE_ASSERT(progNdx < (int)m_programs.size());
626e5c31af7Sopenharmony_ci	DE_ASSERT(m_programData.size() == m_programs.size());
627e5c31af7Sopenharmony_ci
628e5c31af7Sopenharmony_ci	const glw::Functions&	gl			= m_renderCtx.getFunctions();
629e5c31af7Sopenharmony_ci	const ShaderProgram&	program		= *m_programs[progNdx];
630e5c31af7Sopenharmony_ci
631e5c31af7Sopenharmony_ci	vector<AttribSpec>		attributes	= m_programData[progNdx].attributes;
632e5c31af7Sopenharmony_ci
633e5c31af7Sopenharmony_ci	attributes.push_back(AttribSpec("a_position",
634e5c31af7Sopenharmony_ci									Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
635e5c31af7Sopenharmony_ci									Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
636e5c31af7Sopenharmony_ci									Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
637e5c31af7Sopenharmony_ci									Vec4( 1.0f,  1.0f, 0.0f, 1.0f)));
638e5c31af7Sopenharmony_ci
639e5c31af7Sopenharmony_ci	DE_ASSERT(program.isOk());
640e5c31af7Sopenharmony_ci
641e5c31af7Sopenharmony_ci	// Generate vertices.
642e5c31af7Sopenharmony_ci	if (!m_attribBuffers.empty())
643e5c31af7Sopenharmony_ci		gl.deleteBuffers((glw::GLsizei)m_attribBuffers.size(), &m_attribBuffers[0]);
644e5c31af7Sopenharmony_ci	m_attribBuffers.resize(attributes.size(), 0);
645e5c31af7Sopenharmony_ci	gl.genBuffers((glw::GLsizei)m_attribBuffers.size(), &m_attribBuffers[0]);
646e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers()");
647e5c31af7Sopenharmony_ci
648e5c31af7Sopenharmony_ci	for (int attribNdx = 0; attribNdx < (int)attributes.size(); attribNdx++)
649e5c31af7Sopenharmony_ci	{
650e5c31af7Sopenharmony_ci		std::vector<float> vertices;
651e5c31af7Sopenharmony_ci		generateVertices(vertices, m_gridSizeX, m_gridSizeY, attributes[attribNdx]);
652e5c31af7Sopenharmony_ci
653e5c31af7Sopenharmony_ci		gl.bindBuffer(GL_ARRAY_BUFFER, m_attribBuffers[attribNdx]);
654e5c31af7Sopenharmony_ci		gl.bufferData(GL_ARRAY_BUFFER, (glw::GLsizeiptr)(vertices.size()*sizeof(float)), &vertices[0], GL_STATIC_DRAW);
655e5c31af7Sopenharmony_ci		GLU_EXPECT_NO_ERROR(gl.getError(), "Upload buffer data");
656e5c31af7Sopenharmony_ci	}
657e5c31af7Sopenharmony_ci
658e5c31af7Sopenharmony_ci	// Setup attribute bindings.
659e5c31af7Sopenharmony_ci	for (int attribNdx = 0; attribNdx < (int)attributes.size(); attribNdx++)
660e5c31af7Sopenharmony_ci	{
661e5c31af7Sopenharmony_ci		int location = gl.getAttribLocation(program.getProgram(), attributes[attribNdx].name.c_str());
662e5c31af7Sopenharmony_ci
663e5c31af7Sopenharmony_ci		if (location >= 0)
664e5c31af7Sopenharmony_ci		{
665e5c31af7Sopenharmony_ci			gl.enableVertexAttribArray(location);
666e5c31af7Sopenharmony_ci			gl.bindBuffer(GL_ARRAY_BUFFER, m_attribBuffers[attribNdx]);
667e5c31af7Sopenharmony_ci			gl.vertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, 0, DE_NULL);
668e5c31af7Sopenharmony_ci		}
669e5c31af7Sopenharmony_ci	}
670e5c31af7Sopenharmony_ci	GLU_EXPECT_NO_ERROR(gl.getError(), "Setup vertex input state");
671e5c31af7Sopenharmony_ci
672e5c31af7Sopenharmony_ci	gl.useProgram(program.getProgram());
673e5c31af7Sopenharmony_ci	setGeneralUniforms(program.getProgram());
674e5c31af7Sopenharmony_ci	gl.viewport(0, 0, m_viewportWidth, m_viewportHeight);
675e5c31af7Sopenharmony_ci}
676e5c31af7Sopenharmony_ci
677e5c31af7Sopenharmony_civoid OperatorPerformanceCase::prepareWorkload (int progNdx, int workload)
678e5c31af7Sopenharmony_ci{
679e5c31af7Sopenharmony_ci	setWorkloadSizeUniform(m_programs[progNdx]->getProgram(), workload);
680e5c31af7Sopenharmony_ci	render(m_calibrator.getCallCount());
681e5c31af7Sopenharmony_ci}
682e5c31af7Sopenharmony_ci
683e5c31af7Sopenharmony_civoid OperatorPerformanceCase::prepareNextRound (void)
684e5c31af7Sopenharmony_ci{
685e5c31af7Sopenharmony_ci	DE_ASSERT(m_state == STATE_CALIBRATING			||
686e5c31af7Sopenharmony_ci			  m_state == STATE_FIND_HIGH_WORKLOAD	||
687e5c31af7Sopenharmony_ci			  m_state == STATE_MEASURING);
688e5c31af7Sopenharmony_ci
689e5c31af7Sopenharmony_ci	TestLog& log = m_testCtx.getLog();
690e5c31af7Sopenharmony_ci
691e5c31af7Sopenharmony_ci	if (m_state == STATE_CALIBRATING && m_calibrator.getState() == TheilSenCalibrator::STATE_FINISHED)
692e5c31af7Sopenharmony_ci	{
693e5c31af7Sopenharmony_ci		m_measureProgramNdx = 0;
694e5c31af7Sopenharmony_ci		m_state = STATE_FIND_HIGH_WORKLOAD;
695e5c31af7Sopenharmony_ci	}
696e5c31af7Sopenharmony_ci
697e5c31af7Sopenharmony_ci	if (m_state == STATE_CALIBRATING)
698e5c31af7Sopenharmony_ci		prepareWorkload(0, 1);
699e5c31af7Sopenharmony_ci	else if (m_state == STATE_FIND_HIGH_WORKLOAD)
700e5c31af7Sopenharmony_ci	{
701e5c31af7Sopenharmony_ci		vector<WorkloadRecord>& records = m_workloadRecordsFindHigh[m_measureProgramNdx];
702e5c31af7Sopenharmony_ci
703e5c31af7Sopenharmony_ci		if (records.empty() || records.back().getMedianTime() < 2.0f*records[0].getMedianTime())
704e5c31af7Sopenharmony_ci		{
705e5c31af7Sopenharmony_ci			int workloadSize;
706e5c31af7Sopenharmony_ci
707e5c31af7Sopenharmony_ci			if (records.empty())
708e5c31af7Sopenharmony_ci				workloadSize = 1;
709e5c31af7Sopenharmony_ci			else
710e5c31af7Sopenharmony_ci			{
711e5c31af7Sopenharmony_ci				workloadSize = records.back().workloadSize*2;
712e5c31af7Sopenharmony_ci
713e5c31af7Sopenharmony_ci				if (workloadSize > MAX_WORKLOAD_SIZE)
714e5c31af7Sopenharmony_ci				{
715e5c31af7Sopenharmony_ci					log << TestLog::Message << "Even workload size " << records.back().workloadSize
716e5c31af7Sopenharmony_ci											<< " doesn't give high enough frame time for program " << m_measureProgramNdx
717e5c31af7Sopenharmony_ci											<< ". Can't get sensible result." << TestLog::EndMessage;
718e5c31af7Sopenharmony_ci					MEASUREMENT_FAIL();
719e5c31af7Sopenharmony_ci				}
720e5c31af7Sopenharmony_ci			}
721e5c31af7Sopenharmony_ci
722e5c31af7Sopenharmony_ci			records.push_back(WorkloadRecord(workloadSize));
723e5c31af7Sopenharmony_ci			prepareWorkload(0, workloadSize);
724e5c31af7Sopenharmony_ci			m_workloadMeasurementNdx = 0;
725e5c31af7Sopenharmony_ci		}
726e5c31af7Sopenharmony_ci		else
727e5c31af7Sopenharmony_ci		{
728e5c31af7Sopenharmony_ci			m_highWorkloadSizes[m_measureProgramNdx] = records.back().workloadSize;
729e5c31af7Sopenharmony_ci			m_measureProgramNdx++;
730e5c31af7Sopenharmony_ci
731e5c31af7Sopenharmony_ci			if (m_measureProgramNdx >= (int)m_programs.size())
732e5c31af7Sopenharmony_ci			{
733e5c31af7Sopenharmony_ci				m_state = STATE_MEASURING;
734e5c31af7Sopenharmony_ci				m_workloadNdx = -1;
735e5c31af7Sopenharmony_ci				m_measureProgramNdx = 0;
736e5c31af7Sopenharmony_ci			}
737e5c31af7Sopenharmony_ci
738e5c31af7Sopenharmony_ci			prepareProgram(m_measureProgramNdx);
739e5c31af7Sopenharmony_ci			prepareNextRound();
740e5c31af7Sopenharmony_ci		}
741e5c31af7Sopenharmony_ci	}
742e5c31af7Sopenharmony_ci	else
743e5c31af7Sopenharmony_ci	{
744e5c31af7Sopenharmony_ci		m_workloadNdx++;
745e5c31af7Sopenharmony_ci
746e5c31af7Sopenharmony_ci		if (m_workloadNdx < m_numWorkloads)
747e5c31af7Sopenharmony_ci		{
748e5c31af7Sopenharmony_ci			DE_ASSERT(m_numWorkloads > 1);
749e5c31af7Sopenharmony_ci			const int highWorkload	= m_highWorkloadSizes[m_measureProgramNdx];
750e5c31af7Sopenharmony_ci			const int workload		= highWorkload > m_numWorkloads ?
751e5c31af7Sopenharmony_ci										1 + m_workloadNdx*(highWorkload-1)/(m_numWorkloads-1) :
752e5c31af7Sopenharmony_ci										1 + m_workloadNdx;
753e5c31af7Sopenharmony_ci
754e5c31af7Sopenharmony_ci			prepareWorkload(m_measureProgramNdx, workload);
755e5c31af7Sopenharmony_ci
756e5c31af7Sopenharmony_ci			m_workloadMeasurementNdx = 0;
757e5c31af7Sopenharmony_ci
758e5c31af7Sopenharmony_ci			m_workloadRecords[m_measureProgramNdx].push_back(WorkloadRecord(workload));
759e5c31af7Sopenharmony_ci		}
760e5c31af7Sopenharmony_ci		else
761e5c31af7Sopenharmony_ci		{
762e5c31af7Sopenharmony_ci			m_measureProgramNdx++;
763e5c31af7Sopenharmony_ci
764e5c31af7Sopenharmony_ci			if (m_measureProgramNdx < (int)m_programs.size())
765e5c31af7Sopenharmony_ci			{
766e5c31af7Sopenharmony_ci				m_workloadNdx = -1;
767e5c31af7Sopenharmony_ci				m_workloadMeasurementNdx = 0;
768e5c31af7Sopenharmony_ci				prepareProgram(m_measureProgramNdx);
769e5c31af7Sopenharmony_ci				prepareNextRound();
770e5c31af7Sopenharmony_ci			}
771e5c31af7Sopenharmony_ci			else
772e5c31af7Sopenharmony_ci				m_state = STATE_REPORTING;
773e5c31af7Sopenharmony_ci		}
774e5c31af7Sopenharmony_ci	}
775e5c31af7Sopenharmony_ci}
776e5c31af7Sopenharmony_ci
777e5c31af7Sopenharmony_civoid OperatorPerformanceCase::init (void)
778e5c31af7Sopenharmony_ci{
779e5c31af7Sopenharmony_ci	TestLog&				log		= m_testCtx.getLog();
780e5c31af7Sopenharmony_ci	const glw::Functions&	gl		= m_renderCtx.getFunctions();
781e5c31af7Sopenharmony_ci
782e5c31af7Sopenharmony_ci	// Validate that we have sane grid and viewport setup.
783e5c31af7Sopenharmony_ci	DE_ASSERT(de::inBounds(m_gridSizeX, 1, 256) && de::inBounds(m_gridSizeY, 1, 256));
784e5c31af7Sopenharmony_ci	TCU_CHECK(de::inRange(m_viewportWidth,	1, m_renderCtx.getRenderTarget().getWidth()) &&
785e5c31af7Sopenharmony_ci			  de::inRange(m_viewportHeight,	1, m_renderCtx.getRenderTarget().getHeight()));
786e5c31af7Sopenharmony_ci
787e5c31af7Sopenharmony_ci	logRenderTargetInfo(log, m_renderCtx.getRenderTarget());
788e5c31af7Sopenharmony_ci
789e5c31af7Sopenharmony_ci	log << TestLog::Message << "Using additive blending." << TestLog::EndMessage;
790e5c31af7Sopenharmony_ci	gl.enable(GL_BLEND);
791e5c31af7Sopenharmony_ci	gl.blendEquation(GL_FUNC_ADD);
792e5c31af7Sopenharmony_ci	gl.blendFunc(GL_ONE, GL_ONE);
793e5c31af7Sopenharmony_ci
794e5c31af7Sopenharmony_ci	// Generate programs.
795e5c31af7Sopenharmony_ci	DE_ASSERT(m_programs.empty());
796e5c31af7Sopenharmony_ci	m_programData = generateProgramData();
797e5c31af7Sopenharmony_ci	DE_ASSERT(!m_programData.empty());
798e5c31af7Sopenharmony_ci
799e5c31af7Sopenharmony_ci	for (int progNdx = 0; progNdx < (int)m_programData.size(); progNdx++)
800e5c31af7Sopenharmony_ci	{
801e5c31af7Sopenharmony_ci		const string& vert = m_programData[progNdx].vertShaderSource;
802e5c31af7Sopenharmony_ci		const string& frag = m_programData[progNdx].fragShaderSource;
803e5c31af7Sopenharmony_ci
804e5c31af7Sopenharmony_ci		m_programs.push_back(SharedPtr<ShaderProgram>(new ShaderProgram(m_renderCtx, glu::makeVtxFragSources(vert, frag))));
805e5c31af7Sopenharmony_ci
806e5c31af7Sopenharmony_ci		if (!m_programs.back()->isOk())
807e5c31af7Sopenharmony_ci		{
808e5c31af7Sopenharmony_ci			log << *m_programs.back();
809e5c31af7Sopenharmony_ci			TCU_FAIL("Compile failed");
810e5c31af7Sopenharmony_ci		}
811e5c31af7Sopenharmony_ci	}
812e5c31af7Sopenharmony_ci
813e5c31af7Sopenharmony_ci	// Log all programs.
814e5c31af7Sopenharmony_ci	for (int progNdx = 0; progNdx < (int)m_programs.size(); progNdx++)
815e5c31af7Sopenharmony_ci		log << TestLog::Section("Program" + de::toString(progNdx), "Program " + de::toString(progNdx))
816e5c31af7Sopenharmony_ci				<< TestLog::Message << m_programData[progNdx].description << TestLog::EndMessage
817e5c31af7Sopenharmony_ci				<< *m_programs[progNdx]
818e5c31af7Sopenharmony_ci			<< TestLog::EndSection;
819e5c31af7Sopenharmony_ci
820e5c31af7Sopenharmony_ci	m_highWorkloadSizes.resize(m_programData.size());
821e5c31af7Sopenharmony_ci	m_workloadRecordsFindHigh.resize(m_programData.size());
822e5c31af7Sopenharmony_ci	m_workloadRecords.resize(m_programData.size());
823e5c31af7Sopenharmony_ci
824e5c31af7Sopenharmony_ci	m_calibrator.clear(CalibratorParameters(m_initialCalibrationStorage->initialNumCalls, 10 /* calibrate iteration frames */, 2000.0f /* calibrate iteration shortcut threshold (ms) */, 16 /* max calibrate iterations */,
825e5c31af7Sopenharmony_ci											1000.0f/30.0f /* frame time (ms) */, 1000.0f/60.0f /* frame time cap (ms) */, 1000.0f /* target measure duration (ms) */));
826e5c31af7Sopenharmony_ci	m_state = STATE_CALIBRATING;
827e5c31af7Sopenharmony_ci
828e5c31af7Sopenharmony_ci	prepareProgram(0);
829e5c31af7Sopenharmony_ci	prepareNextRound();
830e5c31af7Sopenharmony_ci}
831e5c31af7Sopenharmony_ci
832e5c31af7Sopenharmony_civoid OperatorPerformanceCase::deinit (void)
833e5c31af7Sopenharmony_ci{
834e5c31af7Sopenharmony_ci	if (!m_attribBuffers.empty())
835e5c31af7Sopenharmony_ci	{
836e5c31af7Sopenharmony_ci		m_renderCtx.getFunctions().deleteBuffers((glw::GLsizei)m_attribBuffers.size(), &m_attribBuffers[0]);
837e5c31af7Sopenharmony_ci		m_attribBuffers.clear();
838e5c31af7Sopenharmony_ci	}
839e5c31af7Sopenharmony_ci
840e5c31af7Sopenharmony_ci	m_programs.clear();
841e5c31af7Sopenharmony_ci}
842e5c31af7Sopenharmony_ci
843e5c31af7Sopenharmony_civoid OperatorPerformanceCase::render (int numDrawCalls)
844e5c31af7Sopenharmony_ci{
845e5c31af7Sopenharmony_ci	const glw::Functions&	gl				= m_renderCtx.getFunctions();
846e5c31af7Sopenharmony_ci	const int				numVertices		= getNumVertices(m_gridSizeX, m_gridSizeY);
847e5c31af7Sopenharmony_ci
848e5c31af7Sopenharmony_ci	for (int callNdx = 0; callNdx < numDrawCalls; callNdx++)
849e5c31af7Sopenharmony_ci		gl.drawArrays(GL_TRIANGLES, 0, numVertices);
850e5c31af7Sopenharmony_ci
851e5c31af7Sopenharmony_ci	glu::readPixels(m_renderCtx, 0, 0, tcu::Surface(1, 1).getAccess()); // \note Serves as a more reliable replacement for glFinish().
852e5c31af7Sopenharmony_ci}
853e5c31af7Sopenharmony_ci
854e5c31af7Sopenharmony_cideUint64 OperatorPerformanceCase::renderAndMeasure (int numDrawCalls)
855e5c31af7Sopenharmony_ci{
856e5c31af7Sopenharmony_ci	const deUint64 startTime = deGetMicroseconds();
857e5c31af7Sopenharmony_ci	render(numDrawCalls);
858e5c31af7Sopenharmony_ci	return deGetMicroseconds() - startTime;
859e5c31af7Sopenharmony_ci}
860e5c31af7Sopenharmony_ci
861e5c31af7Sopenharmony_civoid OperatorPerformanceCase::adjustAndLogGridAndViewport (void)
862e5c31af7Sopenharmony_ci{
863e5c31af7Sopenharmony_ci	TestLog& log = m_testCtx.getLog();
864e5c31af7Sopenharmony_ci
865e5c31af7Sopenharmony_ci	// If call count is just 1, and the target frame time still wasn't reached, reduce grid or viewport size.
866e5c31af7Sopenharmony_ci	if (m_calibrator.getCallCount() == 1)
867e5c31af7Sopenharmony_ci	{
868e5c31af7Sopenharmony_ci		const gls::MeasureState&	calibratorMeasure	= m_calibrator.getMeasureState();
869e5c31af7Sopenharmony_ci		const float					drawCallTime		= (float)calibratorMeasure.getTotalTime() / (float)calibratorMeasure.frameTimes.size();
870e5c31af7Sopenharmony_ci		const float					targetDrawCallTime	= m_calibrator.getParameters().targetFrameTimeUs;
871e5c31af7Sopenharmony_ci		const float					targetRatio			= targetDrawCallTime / drawCallTime;
872e5c31af7Sopenharmony_ci
873e5c31af7Sopenharmony_ci		if (targetRatio < 0.95f)
874e5c31af7Sopenharmony_ci		{
875e5c31af7Sopenharmony_ci			// Reduce grid or viewport size assuming draw call time scales proportionally.
876e5c31af7Sopenharmony_ci			if (m_caseType == CASETYPE_VERTEX)
877e5c31af7Sopenharmony_ci			{
878e5c31af7Sopenharmony_ci				const float targetRatioSqrt = deFloatSqrt(targetRatio);
879e5c31af7Sopenharmony_ci				m_gridSizeX = (int)(targetRatioSqrt * (float)m_gridSizeX);
880e5c31af7Sopenharmony_ci				m_gridSizeY = (int)(targetRatioSqrt * (float)m_gridSizeY);
881e5c31af7Sopenharmony_ci				TCU_CHECK_MSG(m_gridSizeX >= 1 && m_gridSizeY >= 1, "Can't decrease grid size enough to achieve low-enough draw times");
882e5c31af7Sopenharmony_ci				log << TestLog::Message << "Note: triangle grid size reduced from original; it's now smaller than during calibration." << TestLog::EndMessage;
883e5c31af7Sopenharmony_ci			}
884e5c31af7Sopenharmony_ci			else
885e5c31af7Sopenharmony_ci			{
886e5c31af7Sopenharmony_ci				const float targetRatioSqrt = deFloatSqrt(targetRatio);
887e5c31af7Sopenharmony_ci				m_viewportWidth  = (int)(targetRatioSqrt * (float)m_viewportWidth);
888e5c31af7Sopenharmony_ci				m_viewportHeight = (int)(targetRatioSqrt * (float)m_viewportHeight);
889e5c31af7Sopenharmony_ci				TCU_CHECK_MSG(m_viewportWidth >= 1 && m_viewportHeight >= 1, "Can't decrease viewport size enough to achieve low-enough draw times");
890e5c31af7Sopenharmony_ci				log << TestLog::Message << "Note: viewport size reduced from original; it's now smaller than during calibration." << TestLog::EndMessage;
891e5c31af7Sopenharmony_ci			}
892e5c31af7Sopenharmony_ci		}
893e5c31af7Sopenharmony_ci	}
894e5c31af7Sopenharmony_ci
895e5c31af7Sopenharmony_ci	prepareProgram(0);
896e5c31af7Sopenharmony_ci
897e5c31af7Sopenharmony_ci	// Log grid and viewport sizes.
898e5c31af7Sopenharmony_ci	log << TestLog::Message << "Grid size: " << m_gridSizeX << "x" << m_gridSizeY << TestLog::EndMessage;
899e5c31af7Sopenharmony_ci	log << TestLog::Message << "Viewport: " << m_viewportWidth << "x" << m_viewportHeight << TestLog::EndMessage;
900e5c31af7Sopenharmony_ci}
901e5c31af7Sopenharmony_ci
902e5c31af7Sopenharmony_ciOperatorPerformanceCase::IterateResult OperatorPerformanceCase::iterate (void)
903e5c31af7Sopenharmony_ci{
904e5c31af7Sopenharmony_ci	const TheilSenCalibrator::State calibratorState = m_calibrator.getState();
905e5c31af7Sopenharmony_ci
906e5c31af7Sopenharmony_ci	if (calibratorState != TheilSenCalibrator::STATE_FINISHED)
907e5c31af7Sopenharmony_ci	{
908e5c31af7Sopenharmony_ci		if (calibratorState == TheilSenCalibrator::STATE_RECOMPUTE_PARAMS)
909e5c31af7Sopenharmony_ci			m_calibrator.recomputeParameters();
910e5c31af7Sopenharmony_ci		else if (calibratorState == TheilSenCalibrator::STATE_MEASURE)
911e5c31af7Sopenharmony_ci			m_calibrator.recordIteration(renderAndMeasure(m_calibrator.getCallCount()));
912e5c31af7Sopenharmony_ci		else
913e5c31af7Sopenharmony_ci			DE_ASSERT(false);
914e5c31af7Sopenharmony_ci
915e5c31af7Sopenharmony_ci		if (m_calibrator.getState() == TheilSenCalibrator::STATE_FINISHED)
916e5c31af7Sopenharmony_ci		{
917e5c31af7Sopenharmony_ci			logCalibrationInfo(m_testCtx.getLog(), m_calibrator);
918e5c31af7Sopenharmony_ci			adjustAndLogGridAndViewport();
919e5c31af7Sopenharmony_ci			prepareNextRound();
920e5c31af7Sopenharmony_ci			m_initialCalibrationStorage->initialNumCalls = m_calibrator.getCallCount();
921e5c31af7Sopenharmony_ci		}
922e5c31af7Sopenharmony_ci	}
923e5c31af7Sopenharmony_ci	else if (m_state == STATE_FIND_HIGH_WORKLOAD || m_state == STATE_MEASURING)
924e5c31af7Sopenharmony_ci	{
925e5c31af7Sopenharmony_ci		if (m_workloadMeasurementNdx < m_numMeasurementsPerWorkload)
926e5c31af7Sopenharmony_ci		{
927e5c31af7Sopenharmony_ci			vector<WorkloadRecord>& records = m_state == STATE_FIND_HIGH_WORKLOAD ? m_workloadRecordsFindHigh[m_measureProgramNdx] : m_workloadRecords[m_measureProgramNdx];
928e5c31af7Sopenharmony_ci			records.back().addFrameTime((float)renderAndMeasure(m_calibrator.getCallCount()));
929e5c31af7Sopenharmony_ci			m_workloadMeasurementNdx++;
930e5c31af7Sopenharmony_ci		}
931e5c31af7Sopenharmony_ci		else
932e5c31af7Sopenharmony_ci			prepareNextRound();
933e5c31af7Sopenharmony_ci	}
934e5c31af7Sopenharmony_ci	else
935e5c31af7Sopenharmony_ci	{
936e5c31af7Sopenharmony_ci		DE_ASSERT(m_state == STATE_REPORTING);
937e5c31af7Sopenharmony_ci
938e5c31af7Sopenharmony_ci		TestLog&	log				= m_testCtx.getLog();
939e5c31af7Sopenharmony_ci		const int	drawCallCount	= m_calibrator.getCallCount();
940e5c31af7Sopenharmony_ci
941e5c31af7Sopenharmony_ci		{
942e5c31af7Sopenharmony_ci			// Compute per-program estimators for measurements.
943e5c31af7Sopenharmony_ci			vector<SegmentedEstimator> estimators;
944e5c31af7Sopenharmony_ci			for (int progNdx = 0; progNdx < (int)m_programs.size(); progNdx++)
945e5c31af7Sopenharmony_ci				estimators.push_back(computeSegmentedEstimator(getWorkloadMedianDataPoints(progNdx)));
946e5c31af7Sopenharmony_ci
947e5c31af7Sopenharmony_ci			// Log measurements and their estimators for all programs.
948e5c31af7Sopenharmony_ci			for (int progNdx = 0; progNdx < (int)m_programs.size(); progNdx++)
949e5c31af7Sopenharmony_ci			{
950e5c31af7Sopenharmony_ci				const SegmentedEstimator&	estimator	= estimators[progNdx];
951e5c31af7Sopenharmony_ci				const string				progNdxStr	= de::toString(progNdx);
952e5c31af7Sopenharmony_ci				vector<WorkloadRecord>		records		= m_workloadRecords[progNdx];
953e5c31af7Sopenharmony_ci				std::sort(records.begin(), records.end());
954e5c31af7Sopenharmony_ci
955e5c31af7Sopenharmony_ci				{
956e5c31af7Sopenharmony_ci					const tcu::ScopedLogSection section(log,
957e5c31af7Sopenharmony_ci														"Program" + progNdxStr + "Measurements",
958e5c31af7Sopenharmony_ci														"Measurements for program " + progNdxStr);
959e5c31af7Sopenharmony_ci
960e5c31af7Sopenharmony_ci					// Sample list of individual frame times.
961e5c31af7Sopenharmony_ci
962e5c31af7Sopenharmony_ci					log << TestLog::SampleList("Program" + progNdxStr + "IndividualFrameTimes", "Individual frame times")
963e5c31af7Sopenharmony_ci						<< TestLog::SampleInfo << TestLog::ValueInfo("Workload",	"Workload",		"",		QP_SAMPLE_VALUE_TAG_PREDICTOR)
964e5c31af7Sopenharmony_ci											   << TestLog::ValueInfo("FrameTime",	"Frame time",	"us",	QP_SAMPLE_VALUE_TAG_RESPONSE)
965e5c31af7Sopenharmony_ci						<< TestLog::EndSampleInfo;
966e5c31af7Sopenharmony_ci
967e5c31af7Sopenharmony_ci					for (int i = 0; i < (int)records.size(); i++)
968e5c31af7Sopenharmony_ci						for (int j = 0; j < (int)records[i].frameTimes.size(); j++)
969e5c31af7Sopenharmony_ci							log << TestLog::Sample << records[i].workloadSize << records[i].frameTimes[j] << TestLog::EndSample;
970e5c31af7Sopenharmony_ci
971e5c31af7Sopenharmony_ci					log << TestLog::EndSampleList;
972e5c31af7Sopenharmony_ci
973e5c31af7Sopenharmony_ci					// Sample list of median frame times.
974e5c31af7Sopenharmony_ci
975e5c31af7Sopenharmony_ci					log << TestLog::SampleList("Program" + progNdxStr + "MedianFrameTimes", "Median frame times")
976e5c31af7Sopenharmony_ci						<< TestLog::SampleInfo << TestLog::ValueInfo("Workload",		"Workload",				"",		QP_SAMPLE_VALUE_TAG_PREDICTOR)
977e5c31af7Sopenharmony_ci											   << TestLog::ValueInfo("MedianFrameTime",	"Median frame time",	"us",	QP_SAMPLE_VALUE_TAG_RESPONSE)
978e5c31af7Sopenharmony_ci						<< TestLog::EndSampleInfo;
979e5c31af7Sopenharmony_ci
980e5c31af7Sopenharmony_ci					for (int i = 0; i < (int)records.size(); i++)
981e5c31af7Sopenharmony_ci						log << TestLog::Sample << records[i].workloadSize << records[i].getMedianTime() << TestLog::EndSample;
982e5c31af7Sopenharmony_ci
983e5c31af7Sopenharmony_ci					log << TestLog::EndSampleList;
984e5c31af7Sopenharmony_ci
985e5c31af7Sopenharmony_ci					log << TestLog::Float("Program" + progNdxStr + "WorkloadCostEstimate", "Workload cost estimate", "us / workload", QP_KEY_TAG_TIME, estimator.right.coefficient);
986e5c31af7Sopenharmony_ci
987e5c31af7Sopenharmony_ci					if (estimator.pivotX > -std::numeric_limits<float>::infinity())
988e5c31af7Sopenharmony_ci						log << TestLog::Message << "Note: the data points with x coordinate greater than or equal to " << estimator.pivotX
989e5c31af7Sopenharmony_ci												<< " seem to form a rising line, and the rest of data points seem to form a near-horizontal line" << TestLog::EndMessage
990e5c31af7Sopenharmony_ci							<< TestLog::Message << "Note: the left line is estimated to be " << lineParamsString(estimator.left)
991e5c31af7Sopenharmony_ci												<< " and the right line " << lineParamsString(estimator.right) << TestLog::EndMessage;
992e5c31af7Sopenharmony_ci					else
993e5c31af7Sopenharmony_ci						log << TestLog::Message << "Note: the data seem to form a single line: " << lineParamsString(estimator.right) << TestLog::EndMessage;
994e5c31af7Sopenharmony_ci				}
995e5c31af7Sopenharmony_ci			}
996e5c31af7Sopenharmony_ci
997e5c31af7Sopenharmony_ci			for (int progNdx = 0; progNdx < (int)m_programs.size(); progNdx++)
998e5c31af7Sopenharmony_ci			{
999e5c31af7Sopenharmony_ci				if (estimators[progNdx].right.coefficient <= 0.0f)
1000e5c31af7Sopenharmony_ci				{
1001e5c31af7Sopenharmony_ci					log << TestLog::Message << "Slope of measurements for program " << progNdx << " isn't positive. Can't get sensible result." << TestLog::EndMessage;
1002e5c31af7Sopenharmony_ci					MEASUREMENT_FAIL();
1003e5c31af7Sopenharmony_ci				}
1004e5c31af7Sopenharmony_ci			}
1005e5c31af7Sopenharmony_ci
1006e5c31af7Sopenharmony_ci			// \note For each estimator, .right.coefficient is the increase in draw time (in microseconds) when
1007e5c31af7Sopenharmony_ci			// incrementing shader workload size by 1, when D draw calls are done, with a vertex/fragment count
1008e5c31af7Sopenharmony_ci			// of R.
1009e5c31af7Sopenharmony_ci			//
1010e5c31af7Sopenharmony_ci			// The measurements of any single program can't tell us the final result (time of single operation),
1011e5c31af7Sopenharmony_ci			// so we use computeSingleOperationTime to compute it from multiple programs' measurements in a
1012e5c31af7Sopenharmony_ci			// subclass-defined manner.
1013e5c31af7Sopenharmony_ci			//
1014e5c31af7Sopenharmony_ci			// After that, microseconds per operation can be calculated as singleOperationTime / (D * R).
1015e5c31af7Sopenharmony_ci
1016e5c31af7Sopenharmony_ci			{
1017e5c31af7Sopenharmony_ci				vector<float>	perProgramSlopes;
1018e5c31af7Sopenharmony_ci				for (int i = 0; i < (int)m_programs.size(); i++)
1019e5c31af7Sopenharmony_ci					perProgramSlopes.push_back(estimators[i].right.coefficient);
1020e5c31af7Sopenharmony_ci
1021e5c31af7Sopenharmony_ci				logSingleOperationCalculationInfo();
1022e5c31af7Sopenharmony_ci
1023e5c31af7Sopenharmony_ci				const float		maxSlope				= *std::max_element(perProgramSlopes.begin(), perProgramSlopes.end());
1024e5c31af7Sopenharmony_ci				const float		usecsPerFramePerOp		= computeSingleOperationTime(perProgramSlopes);
1025e5c31af7Sopenharmony_ci				const int		vertexOrFragmentCount	= m_caseType == CASETYPE_VERTEX ?
1026e5c31af7Sopenharmony_ci															getNumVertices(m_gridSizeX, m_gridSizeY) :
1027e5c31af7Sopenharmony_ci															m_viewportWidth*m_viewportHeight;
1028e5c31af7Sopenharmony_ci				const double	usecsPerDrawCallPerOp	= usecsPerFramePerOp / (double)drawCallCount;
1029e5c31af7Sopenharmony_ci				const double	usecsPerSingleOp		= usecsPerDrawCallPerOp / (double)vertexOrFragmentCount;
1030e5c31af7Sopenharmony_ci				const double	megaOpsPerSecond		= (double)(drawCallCount*vertexOrFragmentCount) / usecsPerFramePerOp;
1031e5c31af7Sopenharmony_ci				const int		numFreeOps				= de::max(0, (int)deFloatFloor(intersectionX(estimators[0].left,
1032e5c31af7Sopenharmony_ci																									 LineParameters(estimators[0].right.offset,
1033e5c31af7Sopenharmony_ci																													usecsPerFramePerOp))));
1034e5c31af7Sopenharmony_ci
1035e5c31af7Sopenharmony_ci				log << TestLog::Integer("VertexOrFragmentCount",
1036e5c31af7Sopenharmony_ci										"R = " + string(m_caseType == CASETYPE_VERTEX ? "Vertex" : "Fragment") + " count",
1037e5c31af7Sopenharmony_ci										"", QP_KEY_TAG_NONE, vertexOrFragmentCount)
1038e5c31af7Sopenharmony_ci
1039e5c31af7Sopenharmony_ci					<< TestLog::Integer("DrawCallsPerFrame", "D = Draw calls per frame", "", QP_KEY_TAG_NONE, drawCallCount)
1040e5c31af7Sopenharmony_ci
1041e5c31af7Sopenharmony_ci					<< TestLog::Integer("VerticesOrFragmentsPerFrame",
1042e5c31af7Sopenharmony_ci										"R*D = " + string(m_caseType == CASETYPE_VERTEX ? "Vertices" : "Fragments") + " per frame",
1043e5c31af7Sopenharmony_ci										"", QP_KEY_TAG_NONE, vertexOrFragmentCount*drawCallCount)
1044e5c31af7Sopenharmony_ci
1045e5c31af7Sopenharmony_ci					<< TestLog::Float("TimePerFramePerOp",
1046e5c31af7Sopenharmony_ci									  "Estimated cost of R*D " + string(m_caseType == CASETYPE_VERTEX ? "vertices" : "fragments")
1047e5c31af7Sopenharmony_ci									  + " (i.e. one frame) with one shader operation",
1048e5c31af7Sopenharmony_ci									  "us", QP_KEY_TAG_TIME, (float)usecsPerFramePerOp)
1049e5c31af7Sopenharmony_ci
1050e5c31af7Sopenharmony_ci					<< TestLog::Float("TimePerDrawcallPerOp",
1051e5c31af7Sopenharmony_ci									  "Estimated cost of one draw call with one shader operation",
1052e5c31af7Sopenharmony_ci									  "us", QP_KEY_TAG_TIME, (float)usecsPerDrawCallPerOp)
1053e5c31af7Sopenharmony_ci
1054e5c31af7Sopenharmony_ci					<< TestLog::Float("TimePerSingleOp",
1055e5c31af7Sopenharmony_ci									  "Estimated cost of a single shader operation",
1056e5c31af7Sopenharmony_ci									  "us", QP_KEY_TAG_TIME, (float)usecsPerSingleOp);
1057e5c31af7Sopenharmony_ci
1058e5c31af7Sopenharmony_ci				// \note Sometimes, when the operation is free or very cheap, it can happen that the shader with the operation runs,
1059e5c31af7Sopenharmony_ci				//		 for some reason, a bit faster than the shader without the operation, and thus we get a negative result. The
1060e5c31af7Sopenharmony_ci				//		 following threshold values for accepting a negative or almost-zero result are rather quick and dirty.
1061e5c31af7Sopenharmony_ci				if (usecsPerFramePerOp <= -0.1f*maxSlope)
1062e5c31af7Sopenharmony_ci				{
1063e5c31af7Sopenharmony_ci					log << TestLog::Message << "Got strongly negative result." << TestLog::EndMessage;
1064e5c31af7Sopenharmony_ci					MEASUREMENT_FAIL();
1065e5c31af7Sopenharmony_ci				}
1066e5c31af7Sopenharmony_ci				else if (usecsPerFramePerOp <= 0.001*maxSlope)
1067e5c31af7Sopenharmony_ci				{
1068e5c31af7Sopenharmony_ci					log << TestLog::Message << "Cost of operation seems to be approximately zero." << TestLog::EndMessage;
1069e5c31af7Sopenharmony_ci					m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1070e5c31af7Sopenharmony_ci				}
1071e5c31af7Sopenharmony_ci				else
1072e5c31af7Sopenharmony_ci				{
1073e5c31af7Sopenharmony_ci					log << TestLog::Float("OpsPerSecond",
1074e5c31af7Sopenharmony_ci										  "Operations per second",
1075e5c31af7Sopenharmony_ci										  "Million/s", QP_KEY_TAG_PERFORMANCE, (float)megaOpsPerSecond)
1076e5c31af7Sopenharmony_ci
1077e5c31af7Sopenharmony_ci						<< TestLog::Integer("NumFreeOps",
1078e5c31af7Sopenharmony_ci											"Estimated number of \"free\" operations",
1079e5c31af7Sopenharmony_ci											"", QP_KEY_TAG_PERFORMANCE, numFreeOps);
1080e5c31af7Sopenharmony_ci
1081e5c31af7Sopenharmony_ci					m_testCtx.setTestResult(QP_TEST_RESULT_PASS, de::floatToString((float)megaOpsPerSecond, 2).c_str());
1082e5c31af7Sopenharmony_ci				}
1083e5c31af7Sopenharmony_ci
1084e5c31af7Sopenharmony_ci				m_state = STATE_FINISHED;
1085e5c31af7Sopenharmony_ci			}
1086e5c31af7Sopenharmony_ci		}
1087e5c31af7Sopenharmony_ci
1088e5c31af7Sopenharmony_ci		return STOP;
1089e5c31af7Sopenharmony_ci	}
1090e5c31af7Sopenharmony_ci
1091e5c31af7Sopenharmony_ci	return CONTINUE;
1092e5c31af7Sopenharmony_ci}
1093e5c31af7Sopenharmony_ci
1094e5c31af7Sopenharmony_ci// Binary operator case.
1095e5c31af7Sopenharmony_ciclass BinaryOpCase : public OperatorPerformanceCase
1096e5c31af7Sopenharmony_ci{
1097e5c31af7Sopenharmony_cipublic:
1098e5c31af7Sopenharmony_ci						BinaryOpCase				(Context& context, const char* name, const char* description, const char* op,
1099e5c31af7Sopenharmony_ci													 glu::DataType type, glu::Precision precision, bool useSwizzle, bool isVertex, const InitialCalibrationStorage& initialCalibration);
1100e5c31af7Sopenharmony_ci
1101e5c31af7Sopenharmony_ciprotected:
1102e5c31af7Sopenharmony_ci	vector<ProgramContext>	generateProgramData					(void) const;
1103e5c31af7Sopenharmony_ci	void					setGeneralUniforms					(deUint32 program) const;
1104e5c31af7Sopenharmony_ci	void					setWorkloadSizeUniform				(deUint32 program, int numOperations) const;
1105e5c31af7Sopenharmony_ci	float					computeSingleOperationTime			(const vector<float>& perProgramOperationCosts) const;
1106e5c31af7Sopenharmony_ci	void					logSingleOperationCalculationInfo	(void) const;
1107e5c31af7Sopenharmony_ci
1108e5c31af7Sopenharmony_ciprivate:
1109e5c31af7Sopenharmony_ci	enum ProgramID
1110e5c31af7Sopenharmony_ci	{
1111e5c31af7Sopenharmony_ci		// \note 0-based sequential numbering is relevant, because these are also used as vector indices.
1112e5c31af7Sopenharmony_ci		// \note The first program should be the heaviest, because OperatorPerformanceCase uses it to reduce grid/viewport size when going too slow.
1113e5c31af7Sopenharmony_ci		PROGRAM_WITH_BIGGER_LOOP = 0,
1114e5c31af7Sopenharmony_ci		PROGRAM_WITH_SMALLER_LOOP,
1115e5c31af7Sopenharmony_ci
1116e5c31af7Sopenharmony_ci		PROGRAM_LAST
1117e5c31af7Sopenharmony_ci	};
1118e5c31af7Sopenharmony_ci
1119e5c31af7Sopenharmony_ci	ProgramContext			generateSingleProgramData		(ProgramID) const;
1120e5c31af7Sopenharmony_ci
1121e5c31af7Sopenharmony_ci	const string			m_op;
1122e5c31af7Sopenharmony_ci	const glu::DataType		m_type;
1123e5c31af7Sopenharmony_ci	const glu::Precision	m_precision;
1124e5c31af7Sopenharmony_ci	const bool				m_useSwizzle;
1125e5c31af7Sopenharmony_ci};
1126e5c31af7Sopenharmony_ci
1127e5c31af7Sopenharmony_ciBinaryOpCase::BinaryOpCase (Context& context, const char* name, const char* description, const char* op,
1128e5c31af7Sopenharmony_ci							glu::DataType type, glu::Precision precision, bool useSwizzle, bool isVertex, const InitialCalibrationStorage& initialCalibration)
1129e5c31af7Sopenharmony_ci	: OperatorPerformanceCase	(context.getTestContext(), context.getRenderContext(), name, description,
1130e5c31af7Sopenharmony_ci								 isVertex ? CASETYPE_VERTEX : CASETYPE_FRAGMENT, NUM_WORKLOADS, initialCalibration)
1131e5c31af7Sopenharmony_ci	, m_op						(op)
1132e5c31af7Sopenharmony_ci	, m_type					(type)
1133e5c31af7Sopenharmony_ci	, m_precision				(precision)
1134e5c31af7Sopenharmony_ci	, m_useSwizzle				(useSwizzle)
1135e5c31af7Sopenharmony_ci{
1136e5c31af7Sopenharmony_ci}
1137e5c31af7Sopenharmony_ci
1138e5c31af7Sopenharmony_ciBinaryOpCase::ProgramContext BinaryOpCase::generateSingleProgramData (ProgramID programID) const
1139e5c31af7Sopenharmony_ci{
1140e5c31af7Sopenharmony_ci	DE_ASSERT(glu::isDataTypeFloatOrVec(m_type) || glu::isDataTypeIntOrIVec(m_type));
1141e5c31af7Sopenharmony_ci
1142e5c31af7Sopenharmony_ci	const bool			isVertexCase	= m_caseType == CASETYPE_VERTEX;
1143e5c31af7Sopenharmony_ci	const char* const	precision		= glu::getPrecisionName(m_precision);
1144e5c31af7Sopenharmony_ci	const char* const	inputPrecision	= glu::isDataTypeIntOrIVec(m_type) && m_precision == glu::PRECISION_LOWP ? "mediump" : precision;
1145e5c31af7Sopenharmony_ci	const char* const	typeName		= getDataTypeName(m_type);
1146e5c31af7Sopenharmony_ci
1147e5c31af7Sopenharmony_ci	std::ostringstream	vtx;
1148e5c31af7Sopenharmony_ci	std::ostringstream	frag;
1149e5c31af7Sopenharmony_ci	std::ostringstream&	op				= isVertexCase ? vtx : frag;
1150e5c31af7Sopenharmony_ci
1151e5c31af7Sopenharmony_ci	// Attributes.
1152e5c31af7Sopenharmony_ci	vtx << "attribute highp vec4 a_position;\n";
1153e5c31af7Sopenharmony_ci	for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS+1; i++)
1154e5c31af7Sopenharmony_ci		vtx << "attribute " << inputPrecision << " vec4 a_in" << i << ";\n";
1155e5c31af7Sopenharmony_ci
1156e5c31af7Sopenharmony_ci	if (isVertexCase)
1157e5c31af7Sopenharmony_ci	{
1158e5c31af7Sopenharmony_ci		vtx << "varying mediump vec4 v_color;\n";
1159e5c31af7Sopenharmony_ci		frag << "varying mediump vec4 v_color;\n";
1160e5c31af7Sopenharmony_ci	}
1161e5c31af7Sopenharmony_ci	else
1162e5c31af7Sopenharmony_ci	{
1163e5c31af7Sopenharmony_ci		for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS+1; i++)
1164e5c31af7Sopenharmony_ci		{
1165e5c31af7Sopenharmony_ci			vtx << "varying " << inputPrecision << " vec4 v_in" << i << ";\n";
1166e5c31af7Sopenharmony_ci			frag << "varying " << inputPrecision << " vec4 v_in" << i << ";\n";
1167e5c31af7Sopenharmony_ci		}
1168e5c31af7Sopenharmony_ci	}
1169e5c31af7Sopenharmony_ci
1170e5c31af7Sopenharmony_ci	op << "uniform mediump int u_numLoopIterations;\n";
1171e5c31af7Sopenharmony_ci	if (isVertexCase)
1172e5c31af7Sopenharmony_ci		op << "uniform mediump float u_zero;\n";
1173e5c31af7Sopenharmony_ci
1174e5c31af7Sopenharmony_ci	vtx << "\n";
1175e5c31af7Sopenharmony_ci	vtx << "void main()\n";
1176e5c31af7Sopenharmony_ci	vtx << "{\n";
1177e5c31af7Sopenharmony_ci
1178e5c31af7Sopenharmony_ci	if (!isVertexCase)
1179e5c31af7Sopenharmony_ci		vtx << "\tgl_Position = a_position;\n";
1180e5c31af7Sopenharmony_ci
1181e5c31af7Sopenharmony_ci	frag << "\n";
1182e5c31af7Sopenharmony_ci	frag << "void main()\n";
1183e5c31af7Sopenharmony_ci	frag << "{\n";
1184e5c31af7Sopenharmony_ci
1185e5c31af7Sopenharmony_ci	// Expression inputs.
1186e5c31af7Sopenharmony_ci	const char* const prefix = isVertexCase ? "a_" : "v_";
1187e5c31af7Sopenharmony_ci	for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS+1; i++)
1188e5c31af7Sopenharmony_ci	{
1189e5c31af7Sopenharmony_ci		const int	inSize		= getDataTypeScalarSize(m_type);
1190e5c31af7Sopenharmony_ci		const bool	isInt		= de::inRange<int>(m_type, TYPE_INT, TYPE_INT_VEC4);
1191e5c31af7Sopenharmony_ci		const bool	cast		= isInt || (!m_useSwizzle && m_type != TYPE_FLOAT_VEC4);
1192e5c31af7Sopenharmony_ci
1193e5c31af7Sopenharmony_ci		op << "\t" << precision << " " << typeName << " in" << i << " = ";
1194e5c31af7Sopenharmony_ci
1195e5c31af7Sopenharmony_ci		if (cast)
1196e5c31af7Sopenharmony_ci			op << typeName << "(";
1197e5c31af7Sopenharmony_ci
1198e5c31af7Sopenharmony_ci		op << prefix << "in" << i;
1199e5c31af7Sopenharmony_ci
1200e5c31af7Sopenharmony_ci		if (m_useSwizzle)
1201e5c31af7Sopenharmony_ci			op << "." << s_swizzles[i % DE_LENGTH_OF_ARRAY(s_swizzles)][inSize-1];
1202e5c31af7Sopenharmony_ci
1203e5c31af7Sopenharmony_ci		if (cast)
1204e5c31af7Sopenharmony_ci			op << ")";
1205e5c31af7Sopenharmony_ci
1206e5c31af7Sopenharmony_ci		op << ";\n";
1207e5c31af7Sopenharmony_ci	}
1208e5c31af7Sopenharmony_ci
1209e5c31af7Sopenharmony_ci	// Operation accumulation variables.
1210e5c31af7Sopenharmony_ci	for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS; i++)
1211e5c31af7Sopenharmony_ci	{
1212e5c31af7Sopenharmony_ci		op << "\t" << precision << " " << typeName << " acc" << i << "a" << " = in" << i+0 << ";\n";
1213e5c31af7Sopenharmony_ci		op << "\t" << precision << " " << typeName << " acc" << i << "b" << " = in" << i+1 << ";\n";
1214e5c31af7Sopenharmony_ci	}
1215e5c31af7Sopenharmony_ci
1216e5c31af7Sopenharmony_ci	// Loop, with expressions in it.
1217e5c31af7Sopenharmony_ci	op << "\tfor (int i = 0; i < u_numLoopIterations; i++)\n";
1218e5c31af7Sopenharmony_ci	op << "\t{\n";
1219e5c31af7Sopenharmony_ci	{
1220e5c31af7Sopenharmony_ci		const int unrollAmount = programID == PROGRAM_WITH_SMALLER_LOOP ? BINARY_OPERATOR_CASE_SMALL_PROGRAM_UNROLL_AMOUNT : BINARY_OPERATOR_CASE_BIG_PROGRAM_UNROLL_AMOUNT;
1221e5c31af7Sopenharmony_ci		for (int unrollNdx = 0; unrollNdx < unrollAmount; unrollNdx++)
1222e5c31af7Sopenharmony_ci		{
1223e5c31af7Sopenharmony_ci			for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS; i++)
1224e5c31af7Sopenharmony_ci			{
1225e5c31af7Sopenharmony_ci				if (i > 0 || unrollNdx > 0)
1226e5c31af7Sopenharmony_ci					op << "\n";
1227e5c31af7Sopenharmony_ci				op << "\t\tacc" << i << "a = acc" << i << "b " << m_op << " acc" << i << "a" << ";\n";
1228e5c31af7Sopenharmony_ci				op << "\t\tacc" << i << "b = acc" << i << "a " << m_op << " acc" << i << "b" << ";\n";
1229e5c31af7Sopenharmony_ci			}
1230e5c31af7Sopenharmony_ci		}
1231e5c31af7Sopenharmony_ci	}
1232e5c31af7Sopenharmony_ci	op << "\t}\n";
1233e5c31af7Sopenharmony_ci	op << "\n";
1234e5c31af7Sopenharmony_ci
1235e5c31af7Sopenharmony_ci	// Result variable (sum of accumulation variables).
1236e5c31af7Sopenharmony_ci	op << "\t" << precision << " " << typeName << " res =";
1237e5c31af7Sopenharmony_ci	for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS; i++)
1238e5c31af7Sopenharmony_ci		op << (i > 0 ? " "+m_op : "") << " acc" << i << "b";
1239e5c31af7Sopenharmony_ci	op << ";\n";
1240e5c31af7Sopenharmony_ci
1241e5c31af7Sopenharmony_ci	// Convert to color.
1242e5c31af7Sopenharmony_ci	op << "\tmediump vec4 color = ";
1243e5c31af7Sopenharmony_ci	if (m_type == TYPE_FLOAT_VEC4)
1244e5c31af7Sopenharmony_ci		op << "res";
1245e5c31af7Sopenharmony_ci	else
1246e5c31af7Sopenharmony_ci	{
1247e5c31af7Sopenharmony_ci		int size = getDataTypeScalarSize(m_type);
1248e5c31af7Sopenharmony_ci		op << "vec4(res";
1249e5c31af7Sopenharmony_ci
1250e5c31af7Sopenharmony_ci		for (int i = size; i < 4; i++)
1251e5c31af7Sopenharmony_ci			op << ", " << (i == 3 ? "1.0" : "0.0");
1252e5c31af7Sopenharmony_ci
1253e5c31af7Sopenharmony_ci		op << ")";
1254e5c31af7Sopenharmony_ci	}
1255e5c31af7Sopenharmony_ci	op << ";\n";
1256e5c31af7Sopenharmony_ci	op << "\t" << (isVertexCase ? "v_color" : "gl_FragColor") << " = color;\n";
1257e5c31af7Sopenharmony_ci
1258e5c31af7Sopenharmony_ci	if (isVertexCase)
1259e5c31af7Sopenharmony_ci	{
1260e5c31af7Sopenharmony_ci		vtx << "	gl_Position = a_position + u_zero*color;\n";
1261e5c31af7Sopenharmony_ci		frag << "	gl_FragColor = v_color;\n";
1262e5c31af7Sopenharmony_ci	}
1263e5c31af7Sopenharmony_ci	else
1264e5c31af7Sopenharmony_ci	{
1265e5c31af7Sopenharmony_ci		for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS+1; i++)
1266e5c31af7Sopenharmony_ci			vtx << "	v_in" << i << " = a_in" << i << ";\n";
1267e5c31af7Sopenharmony_ci	}
1268e5c31af7Sopenharmony_ci
1269e5c31af7Sopenharmony_ci	vtx << "}\n";
1270e5c31af7Sopenharmony_ci	frag << "}\n";
1271e5c31af7Sopenharmony_ci
1272e5c31af7Sopenharmony_ci	{
1273e5c31af7Sopenharmony_ci		vector<AttribSpec> attributes;
1274e5c31af7Sopenharmony_ci		for (int i = 0; i < BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS+1; i++)
1275e5c31af7Sopenharmony_ci			attributes.push_back(AttribSpec(("a_in" + de::toString(i)).c_str(),
1276e5c31af7Sopenharmony_ci											Vec4(2.0f, 2.0f, 2.0f, 1.0f).swizzle((i+0)%4, (i+1)%4, (i+2)%4, (i+3)%4),
1277e5c31af7Sopenharmony_ci											Vec4(1.0f, 2.0f, 1.0f, 2.0f).swizzle((i+0)%4, (i+1)%4, (i+2)%4, (i+3)%4),
1278e5c31af7Sopenharmony_ci											Vec4(2.0f, 1.0f, 2.0f, 2.0f).swizzle((i+0)%4, (i+1)%4, (i+2)%4, (i+3)%4),
1279e5c31af7Sopenharmony_ci											Vec4(1.0f, 1.0f, 2.0f, 1.0f).swizzle((i+0)%4, (i+1)%4, (i+2)%4, (i+3)%4)));
1280e5c31af7Sopenharmony_ci
1281e5c31af7Sopenharmony_ci		{
1282e5c31af7Sopenharmony_ci			string description = "This is the program with the ";
1283e5c31af7Sopenharmony_ci
1284e5c31af7Sopenharmony_ci			description += programID == PROGRAM_WITH_SMALLER_LOOP	? "smaller"
1285e5c31af7Sopenharmony_ci						 : programID == PROGRAM_WITH_BIGGER_LOOP	? "bigger"
1286e5c31af7Sopenharmony_ci						 : DE_NULL;
1287e5c31af7Sopenharmony_ci
1288e5c31af7Sopenharmony_ci			description += " loop.\n"
1289e5c31af7Sopenharmony_ci						   "Note: workload size for this program means the number of loop iterations.";
1290e5c31af7Sopenharmony_ci
1291e5c31af7Sopenharmony_ci			return ProgramContext(vtx.str(), frag.str(), attributes, description);
1292e5c31af7Sopenharmony_ci		}
1293e5c31af7Sopenharmony_ci	}
1294e5c31af7Sopenharmony_ci}
1295e5c31af7Sopenharmony_ci
1296e5c31af7Sopenharmony_civector<BinaryOpCase::ProgramContext> BinaryOpCase::generateProgramData (void) const
1297e5c31af7Sopenharmony_ci{
1298e5c31af7Sopenharmony_ci	vector<ProgramContext> progData;
1299e5c31af7Sopenharmony_ci	for (int i = 0; i < PROGRAM_LAST; i++)
1300e5c31af7Sopenharmony_ci		progData.push_back(generateSingleProgramData((ProgramID)i));
1301e5c31af7Sopenharmony_ci	return progData;
1302e5c31af7Sopenharmony_ci}
1303e5c31af7Sopenharmony_ci
1304e5c31af7Sopenharmony_civoid BinaryOpCase::setGeneralUniforms (deUint32 program) const
1305e5c31af7Sopenharmony_ci{
1306e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_renderCtx.getFunctions();
1307e5c31af7Sopenharmony_ci	gl.uniform1f(gl.getUniformLocation(program, "u_zero"), 0.0f);
1308e5c31af7Sopenharmony_ci}
1309e5c31af7Sopenharmony_ci
1310e5c31af7Sopenharmony_civoid BinaryOpCase::setWorkloadSizeUniform (deUint32 program, int numLoopIterations) const
1311e5c31af7Sopenharmony_ci{
1312e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_renderCtx.getFunctions();
1313e5c31af7Sopenharmony_ci	gl.uniform1i(gl.getUniformLocation(program, "u_numLoopIterations"), numLoopIterations);
1314e5c31af7Sopenharmony_ci}
1315e5c31af7Sopenharmony_ci
1316e5c31af7Sopenharmony_cifloat BinaryOpCase::computeSingleOperationTime (const vector<float>& perProgramOperationCosts) const
1317e5c31af7Sopenharmony_ci{
1318e5c31af7Sopenharmony_ci	DE_ASSERT(perProgramOperationCosts.size() == PROGRAM_LAST);
1319e5c31af7Sopenharmony_ci
1320e5c31af7Sopenharmony_ci	const int		baseNumOpsInsideLoop				= 2 * BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS;
1321e5c31af7Sopenharmony_ci	const int		numOpsInsideLoopInSmallProgram		= baseNumOpsInsideLoop * BINARY_OPERATOR_CASE_SMALL_PROGRAM_UNROLL_AMOUNT;
1322e5c31af7Sopenharmony_ci	const int		numOpsInsideLoopInBigProgram		= baseNumOpsInsideLoop * BINARY_OPERATOR_CASE_BIG_PROGRAM_UNROLL_AMOUNT;
1323e5c31af7Sopenharmony_ci	DE_STATIC_ASSERT(numOpsInsideLoopInBigProgram > numOpsInsideLoopInSmallProgram);
1324e5c31af7Sopenharmony_ci	const int		opDiff								= numOpsInsideLoopInBigProgram - numOpsInsideLoopInSmallProgram;
1325e5c31af7Sopenharmony_ci	const float		programOperationCostDiff			= perProgramOperationCosts[PROGRAM_WITH_BIGGER_LOOP] - perProgramOperationCosts[PROGRAM_WITH_SMALLER_LOOP];
1326e5c31af7Sopenharmony_ci
1327e5c31af7Sopenharmony_ci	return programOperationCostDiff / (float)opDiff;
1328e5c31af7Sopenharmony_ci}
1329e5c31af7Sopenharmony_ci
1330e5c31af7Sopenharmony_civoid BinaryOpCase::logSingleOperationCalculationInfo (void) const
1331e5c31af7Sopenharmony_ci{
1332e5c31af7Sopenharmony_ci	const int			baseNumOpsInsideLoop			= 2 * BINARY_OPERATOR_CASE_NUM_INDEPENDENT_CALCULATIONS;
1333e5c31af7Sopenharmony_ci	const int			numOpsInsideLoopInSmallProgram	= baseNumOpsInsideLoop * BINARY_OPERATOR_CASE_SMALL_PROGRAM_UNROLL_AMOUNT;
1334e5c31af7Sopenharmony_ci	const int			numOpsInsideLoopInBigProgram	= baseNumOpsInsideLoop * BINARY_OPERATOR_CASE_BIG_PROGRAM_UNROLL_AMOUNT;
1335e5c31af7Sopenharmony_ci	const int			opDiff							= numOpsInsideLoopInBigProgram - numOpsInsideLoopInSmallProgram;
1336e5c31af7Sopenharmony_ci	const char* const	opName							= m_op == "+" ? "addition"
1337e5c31af7Sopenharmony_ci														: m_op == "-" ? "subtraction"
1338e5c31af7Sopenharmony_ci														: m_op == "*" ? "multiplication"
1339e5c31af7Sopenharmony_ci														: m_op == "/" ? "division"
1340e5c31af7Sopenharmony_ci														: DE_NULL;
1341e5c31af7Sopenharmony_ci	DE_ASSERT(opName != DE_NULL);
1342e5c31af7Sopenharmony_ci
1343e5c31af7Sopenharmony_ci	m_testCtx.getLog() << TestLog::Message << "Note: the bigger program contains " << opDiff << " more "
1344e5c31af7Sopenharmony_ci										   << opName << " operations in one loop iteration than the small program; "
1345e5c31af7Sopenharmony_ci										   << "cost of one operation is calculated as (cost_of_bigger_workload - cost_of_smaller_workload) / " << opDiff
1346e5c31af7Sopenharmony_ci										   << TestLog::EndMessage;
1347e5c31af7Sopenharmony_ci}
1348e5c31af7Sopenharmony_ci
1349e5c31af7Sopenharmony_ci// Built-in function case.
1350e5c31af7Sopenharmony_ciclass FunctionCase : public OperatorPerformanceCase
1351e5c31af7Sopenharmony_ci{
1352e5c31af7Sopenharmony_cipublic:
1353e5c31af7Sopenharmony_ci	enum
1354e5c31af7Sopenharmony_ci	{
1355e5c31af7Sopenharmony_ci		MAX_PARAMS = 3
1356e5c31af7Sopenharmony_ci	};
1357e5c31af7Sopenharmony_ci
1358e5c31af7Sopenharmony_ci						FunctionCase			(Context&							context,
1359e5c31af7Sopenharmony_ci												 const char*						name,
1360e5c31af7Sopenharmony_ci												 const char*						description,
1361e5c31af7Sopenharmony_ci												 const char*						func,
1362e5c31af7Sopenharmony_ci												 glu::DataType						returnType,
1363e5c31af7Sopenharmony_ci												 const glu::DataType				paramTypes[MAX_PARAMS],
1364e5c31af7Sopenharmony_ci												 const Vec4&						attribute,
1365e5c31af7Sopenharmony_ci												 int								modifyParamNdx, //!< Add a compile-time constant (2.0) to the parameter at this index. This is ignored if negative.
1366e5c31af7Sopenharmony_ci												 bool								useNearlyConstantINputs, //!< Function inputs shouldn't be much bigger than 'attribute'.
1367e5c31af7Sopenharmony_ci												 glu::Precision						precision,
1368e5c31af7Sopenharmony_ci												 bool								isVertex,
1369e5c31af7Sopenharmony_ci												 const InitialCalibrationStorage&	initialCalibration);
1370e5c31af7Sopenharmony_ci
1371e5c31af7Sopenharmony_ciprotected:
1372e5c31af7Sopenharmony_ci	vector<ProgramContext>	generateProgramData					(void) const;
1373e5c31af7Sopenharmony_ci	void					setGeneralUniforms					(deUint32 program) const;
1374e5c31af7Sopenharmony_ci	void					setWorkloadSizeUniform				(deUint32 program, int numOperations) const;
1375e5c31af7Sopenharmony_ci	float					computeSingleOperationTime			(const vector<float>& perProgramOperationCosts) const;
1376e5c31af7Sopenharmony_ci	void					logSingleOperationCalculationInfo	(void) const;
1377e5c31af7Sopenharmony_ci
1378e5c31af7Sopenharmony_ciprivate:
1379e5c31af7Sopenharmony_ci	enum ProgramID
1380e5c31af7Sopenharmony_ci	{
1381e5c31af7Sopenharmony_ci		// \note 0-based sequential numbering is relevant, because these are also used as vector indices.
1382e5c31af7Sopenharmony_ci		// \note The first program should be the heaviest, because OperatorPerformanceCase uses it to reduce grid/viewport size when going too slow.
1383e5c31af7Sopenharmony_ci		PROGRAM_WITH_FUNCTION_CALLS = 0,
1384e5c31af7Sopenharmony_ci		PROGRAM_WITHOUT_FUNCTION_CALLS,
1385e5c31af7Sopenharmony_ci
1386e5c31af7Sopenharmony_ci		PROGRAM_LAST
1387e5c31af7Sopenharmony_ci	};
1388e5c31af7Sopenharmony_ci
1389e5c31af7Sopenharmony_ci	//! Forms a "sum" expression from aExpr and bExpr; for booleans, this is "equal(a,b)", otherwise actual sum.
1390e5c31af7Sopenharmony_ci	static string		sumExpr						(const string& aExpr, const string& bExpr, glu::DataType type);
1391e5c31af7Sopenharmony_ci	//! Forms an expression used to increment an input value in the shader. If type is boolean, this is just
1392e5c31af7Sopenharmony_ci	//! baseExpr; otherwise, baseExpr is modified by multiplication or division by a loop index,
1393e5c31af7Sopenharmony_ci	//! to prevent simple compiler optimizations. See m_useNearlyConstantInputs for more explanation.
1394e5c31af7Sopenharmony_ci	static string		incrementExpr				(const string& baseExpr, glu::DataType type, bool divide);
1395e5c31af7Sopenharmony_ci
1396e5c31af7Sopenharmony_ci	ProgramContext		generateSingleProgramData	(ProgramID) const;
1397e5c31af7Sopenharmony_ci
1398e5c31af7Sopenharmony_ci	const string			m_func;
1399e5c31af7Sopenharmony_ci	const glu::DataType		m_returnType;
1400e5c31af7Sopenharmony_ci	glu::DataType			m_paramTypes[MAX_PARAMS];
1401e5c31af7Sopenharmony_ci	// \note m_modifyParamNdx, if not negative, specifies the index of the parameter to which a
1402e5c31af7Sopenharmony_ci	//		 compile-time constant (2.0) is added. This is a quick and dirty way to deal with
1403e5c31af7Sopenharmony_ci	//		 functions like clamp or smoothstep that require that a certain parameter is
1404e5c31af7Sopenharmony_ci	//		 greater than a certain other parameter.
1405e5c31af7Sopenharmony_ci	const int				m_modifyParamNdx;
1406e5c31af7Sopenharmony_ci	// \note m_useNearlyConstantInputs determines whether the inputs given to the function
1407e5c31af7Sopenharmony_ci	//		 should increase (w.r.t m_attribute) only by very small amounts. This is relevant
1408e5c31af7Sopenharmony_ci	//		 for functions like asin, which requires its inputs to be in a specific range.
1409e5c31af7Sopenharmony_ci	//		 In practice, this affects whether expressions used to increment the input
1410e5c31af7Sopenharmony_ci	//		 variables use division instead of multiplication; normally, multiplication is used,
1411e5c31af7Sopenharmony_ci	//		 but it's hard to keep the increments very small that way, and division shouldn't
1412e5c31af7Sopenharmony_ci	//		 be the default, since for many functions (probably not asin, luckily), division
1413e5c31af7Sopenharmony_ci	//		 is too heavy and dominates time-wise.
1414e5c31af7Sopenharmony_ci	const bool				m_useNearlyConstantInputs;
1415e5c31af7Sopenharmony_ci	const Vec4				m_attribute;
1416e5c31af7Sopenharmony_ci	const glu::Precision	m_precision;
1417e5c31af7Sopenharmony_ci};
1418e5c31af7Sopenharmony_ci
1419e5c31af7Sopenharmony_ciFunctionCase::FunctionCase (Context&							context,
1420e5c31af7Sopenharmony_ci							const char*							name,
1421e5c31af7Sopenharmony_ci							const char*							description,
1422e5c31af7Sopenharmony_ci							const char*							func,
1423e5c31af7Sopenharmony_ci							glu::DataType						returnType,
1424e5c31af7Sopenharmony_ci							const glu::DataType					paramTypes[MAX_PARAMS],
1425e5c31af7Sopenharmony_ci							const Vec4&							attribute,
1426e5c31af7Sopenharmony_ci							int									modifyParamNdx,
1427e5c31af7Sopenharmony_ci							bool								useNearlyConstantInputs,
1428e5c31af7Sopenharmony_ci							glu::Precision						precision,
1429e5c31af7Sopenharmony_ci							bool								isVertex,
1430e5c31af7Sopenharmony_ci							const InitialCalibrationStorage&	initialCalibration)
1431e5c31af7Sopenharmony_ci	: OperatorPerformanceCase	(context.getTestContext(), context.getRenderContext(), name, description,
1432e5c31af7Sopenharmony_ci								 isVertex ? CASETYPE_VERTEX : CASETYPE_FRAGMENT, NUM_WORKLOADS, initialCalibration)
1433e5c31af7Sopenharmony_ci	, m_func					(func)
1434e5c31af7Sopenharmony_ci	, m_returnType				(returnType)
1435e5c31af7Sopenharmony_ci	, m_modifyParamNdx			(modifyParamNdx)
1436e5c31af7Sopenharmony_ci	, m_useNearlyConstantInputs	(useNearlyConstantInputs)
1437e5c31af7Sopenharmony_ci	, m_attribute				(attribute)
1438e5c31af7Sopenharmony_ci	, m_precision				(precision)
1439e5c31af7Sopenharmony_ci{
1440e5c31af7Sopenharmony_ci	for (int i = 0; i < MAX_PARAMS; i++)
1441e5c31af7Sopenharmony_ci		m_paramTypes[i] = paramTypes[i];
1442e5c31af7Sopenharmony_ci}
1443e5c31af7Sopenharmony_ci
1444e5c31af7Sopenharmony_cistring FunctionCase::sumExpr (const string& aExpr, const string& bExpr, glu::DataType type)
1445e5c31af7Sopenharmony_ci{
1446e5c31af7Sopenharmony_ci	if (glu::isDataTypeBoolOrBVec(type))
1447e5c31af7Sopenharmony_ci	{
1448e5c31af7Sopenharmony_ci		if (type == glu::TYPE_BOOL)
1449e5c31af7Sopenharmony_ci			return "(" + aExpr + " == " + bExpr + ")";
1450e5c31af7Sopenharmony_ci		else
1451e5c31af7Sopenharmony_ci			return "equal(" + aExpr + ", " + bExpr + ")";
1452e5c31af7Sopenharmony_ci	}
1453e5c31af7Sopenharmony_ci	else
1454e5c31af7Sopenharmony_ci		return "(" + aExpr + " + " + bExpr + ")";
1455e5c31af7Sopenharmony_ci}
1456e5c31af7Sopenharmony_ci
1457e5c31af7Sopenharmony_cistring FunctionCase::incrementExpr (const string& baseExpr, glu::DataType type, bool divide)
1458e5c31af7Sopenharmony_ci{
1459e5c31af7Sopenharmony_ci	const string mulOrDiv = divide ? "/" : "*";
1460e5c31af7Sopenharmony_ci
1461e5c31af7Sopenharmony_ci	return glu::isDataTypeBoolOrBVec(type)	? baseExpr
1462e5c31af7Sopenharmony_ci		 : glu::isDataTypeIntOrIVec(type)	? "(" + baseExpr + mulOrDiv + "(i+1))"
1463e5c31af7Sopenharmony_ci		 :									  "(" + baseExpr + mulOrDiv + "float(i+1))";
1464e5c31af7Sopenharmony_ci}
1465e5c31af7Sopenharmony_ci
1466e5c31af7Sopenharmony_ciFunctionCase::ProgramContext FunctionCase::generateSingleProgramData (ProgramID programID) const
1467e5c31af7Sopenharmony_ci{
1468e5c31af7Sopenharmony_ci	const bool			isVertexCase			= m_caseType == CASETYPE_VERTEX;
1469e5c31af7Sopenharmony_ci	const char* const	precision				= glu::getPrecisionName(m_precision);
1470e5c31af7Sopenharmony_ci	const char* const	returnTypeName			= getDataTypeName(m_returnType);
1471e5c31af7Sopenharmony_ci	const string		returnPrecisionMaybe	= glu::isDataTypeBoolOrBVec(m_returnType) ? "" : string() + precision + " ";
1472e5c31af7Sopenharmony_ci	const char*			inputPrecision			= DE_NULL;
1473e5c31af7Sopenharmony_ci	const bool			isMatrixReturn			= isDataTypeMatrix(m_returnType);
1474e5c31af7Sopenharmony_ci	int					numParams				= 0;
1475e5c31af7Sopenharmony_ci	const char*			paramTypeNames[MAX_PARAMS];
1476e5c31af7Sopenharmony_ci	string				paramPrecisionsMaybe[MAX_PARAMS];
1477e5c31af7Sopenharmony_ci
1478e5c31af7Sopenharmony_ci	for (int i = 0; i < MAX_PARAMS; i++)
1479e5c31af7Sopenharmony_ci	{
1480e5c31af7Sopenharmony_ci		paramTypeNames[i]			= getDataTypeName(m_paramTypes[i]);
1481e5c31af7Sopenharmony_ci		paramPrecisionsMaybe[i]		= glu::isDataTypeBoolOrBVec(m_paramTypes[i]) ? "" : string() + precision + " ";
1482e5c31af7Sopenharmony_ci
1483e5c31af7Sopenharmony_ci		if (inputPrecision == DE_NULL && isDataTypeIntOrIVec(m_paramTypes[i]) && m_precision == glu::PRECISION_LOWP)
1484e5c31af7Sopenharmony_ci			inputPrecision = "mediump";
1485e5c31af7Sopenharmony_ci
1486e5c31af7Sopenharmony_ci		if (m_paramTypes[i] != TYPE_INVALID)
1487e5c31af7Sopenharmony_ci			numParams = i+1;
1488e5c31af7Sopenharmony_ci	}
1489e5c31af7Sopenharmony_ci
1490e5c31af7Sopenharmony_ci	DE_ASSERT(numParams > 0);
1491e5c31af7Sopenharmony_ci
1492e5c31af7Sopenharmony_ci	if (inputPrecision == DE_NULL)
1493e5c31af7Sopenharmony_ci		inputPrecision = precision;
1494e5c31af7Sopenharmony_ci
1495e5c31af7Sopenharmony_ci	int						numAttributes	= FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS + numParams - 1;
1496e5c31af7Sopenharmony_ci	std::ostringstream		vtx;
1497e5c31af7Sopenharmony_ci	std::ostringstream		frag;
1498e5c31af7Sopenharmony_ci	std::ostringstream&		op				= isVertexCase ? vtx : frag;
1499e5c31af7Sopenharmony_ci
1500e5c31af7Sopenharmony_ci	// Attributes.
1501e5c31af7Sopenharmony_ci	vtx << "attribute highp vec4 a_position;\n";
1502e5c31af7Sopenharmony_ci	for (int i = 0; i < numAttributes; i++)
1503e5c31af7Sopenharmony_ci		vtx << "attribute " << inputPrecision << " vec4 a_in" << i << ";\n";
1504e5c31af7Sopenharmony_ci
1505e5c31af7Sopenharmony_ci	if (isVertexCase)
1506e5c31af7Sopenharmony_ci	{
1507e5c31af7Sopenharmony_ci		vtx << "varying mediump vec4 v_color;\n";
1508e5c31af7Sopenharmony_ci		frag << "varying mediump vec4 v_color;\n";
1509e5c31af7Sopenharmony_ci	}
1510e5c31af7Sopenharmony_ci	else
1511e5c31af7Sopenharmony_ci	{
1512e5c31af7Sopenharmony_ci		for (int i = 0; i < numAttributes; i++)
1513e5c31af7Sopenharmony_ci		{
1514e5c31af7Sopenharmony_ci			vtx << "varying " << inputPrecision << " vec4 v_in" << i << ";\n";
1515e5c31af7Sopenharmony_ci			frag << "varying " << inputPrecision << " vec4 v_in" << i << ";\n";
1516e5c31af7Sopenharmony_ci		}
1517e5c31af7Sopenharmony_ci	}
1518e5c31af7Sopenharmony_ci
1519e5c31af7Sopenharmony_ci	op << "uniform mediump int u_numLoopIterations;\n";
1520e5c31af7Sopenharmony_ci	if (isVertexCase)
1521e5c31af7Sopenharmony_ci		op << "uniform mediump float u_zero;\n";
1522e5c31af7Sopenharmony_ci
1523e5c31af7Sopenharmony_ci	for (int paramNdx = 0; paramNdx < numParams; paramNdx++)
1524e5c31af7Sopenharmony_ci		op << "uniform " << paramPrecisionsMaybe[paramNdx] << paramTypeNames[paramNdx] << " u_inc" << (char)('A'+paramNdx) << ";\n";
1525e5c31af7Sopenharmony_ci
1526e5c31af7Sopenharmony_ci	vtx << "\n";
1527e5c31af7Sopenharmony_ci	vtx << "void main()\n";
1528e5c31af7Sopenharmony_ci	vtx << "{\n";
1529e5c31af7Sopenharmony_ci
1530e5c31af7Sopenharmony_ci	if (!isVertexCase)
1531e5c31af7Sopenharmony_ci		vtx << "\tgl_Position = a_position;\n";
1532e5c31af7Sopenharmony_ci
1533e5c31af7Sopenharmony_ci	frag << "\n";
1534e5c31af7Sopenharmony_ci	frag << "void main()\n";
1535e5c31af7Sopenharmony_ci	frag << "{\n";
1536e5c31af7Sopenharmony_ci
1537e5c31af7Sopenharmony_ci	// Function call input and return value accumulation variables.
1538e5c31af7Sopenharmony_ci	{
1539e5c31af7Sopenharmony_ci		const char* const inPrefix = isVertexCase ? "a_" : "v_";
1540e5c31af7Sopenharmony_ci
1541e5c31af7Sopenharmony_ci		for (int calcNdx = 0; calcNdx < FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS; calcNdx++)
1542e5c31af7Sopenharmony_ci		{
1543e5c31af7Sopenharmony_ci			for (int paramNdx = 0; paramNdx < numParams; paramNdx++)
1544e5c31af7Sopenharmony_ci			{
1545e5c31af7Sopenharmony_ci				const glu::DataType		paramType	= m_paramTypes[paramNdx];
1546e5c31af7Sopenharmony_ci				const bool				mustCast	= paramType != glu::TYPE_FLOAT_VEC4;
1547e5c31af7Sopenharmony_ci
1548e5c31af7Sopenharmony_ci				op << "\t" << paramPrecisionsMaybe[paramNdx] << paramTypeNames[paramNdx] << " in" << calcNdx << (char)('a'+paramNdx) << " = ";
1549e5c31af7Sopenharmony_ci
1550e5c31af7Sopenharmony_ci				if (mustCast)
1551e5c31af7Sopenharmony_ci					op << paramTypeNames[paramNdx] << "(";
1552e5c31af7Sopenharmony_ci
1553e5c31af7Sopenharmony_ci				if (glu::isDataTypeMatrix(paramType))
1554e5c31af7Sopenharmony_ci				{
1555e5c31af7Sopenharmony_ci					static const char* const	swizzles[3]		= { "x", "xy", "xyz" };
1556e5c31af7Sopenharmony_ci					const int					numRows			= glu::getDataTypeMatrixNumRows(paramType);
1557e5c31af7Sopenharmony_ci					const int					numCols			= glu::getDataTypeMatrixNumColumns(paramType);
1558e5c31af7Sopenharmony_ci					const string				swizzle			= numRows < 4 ? string() + "." + swizzles[numRows-1] : "";
1559e5c31af7Sopenharmony_ci
1560e5c31af7Sopenharmony_ci					for (int i = 0; i < numCols; i++)
1561e5c31af7Sopenharmony_ci						op << (i > 0 ? ", " : "") << inPrefix << "in" << calcNdx+paramNdx << swizzle;
1562e5c31af7Sopenharmony_ci				}
1563e5c31af7Sopenharmony_ci				else
1564e5c31af7Sopenharmony_ci				{
1565e5c31af7Sopenharmony_ci					op << inPrefix << "in" << calcNdx+paramNdx;
1566e5c31af7Sopenharmony_ci
1567e5c31af7Sopenharmony_ci					if (paramNdx == m_modifyParamNdx)
1568e5c31af7Sopenharmony_ci					{
1569e5c31af7Sopenharmony_ci						DE_ASSERT(glu::isDataTypeFloatOrVec(paramType));
1570e5c31af7Sopenharmony_ci						op << " + 2.0";
1571e5c31af7Sopenharmony_ci					}
1572e5c31af7Sopenharmony_ci				}
1573e5c31af7Sopenharmony_ci
1574e5c31af7Sopenharmony_ci				if (mustCast)
1575e5c31af7Sopenharmony_ci					op << ")";
1576e5c31af7Sopenharmony_ci
1577e5c31af7Sopenharmony_ci				op << ";\n";
1578e5c31af7Sopenharmony_ci			}
1579e5c31af7Sopenharmony_ci
1580e5c31af7Sopenharmony_ci			op << "\t" << returnPrecisionMaybe << returnTypeName << " res" << calcNdx << " = " << returnTypeName << "(0);\n";
1581e5c31af7Sopenharmony_ci		}
1582e5c31af7Sopenharmony_ci	}
1583e5c31af7Sopenharmony_ci
1584e5c31af7Sopenharmony_ci	// Loop with expressions in it.
1585e5c31af7Sopenharmony_ci	op << "\tfor (int i = 0; i < u_numLoopIterations; i++)\n";
1586e5c31af7Sopenharmony_ci	op << "\t{\n";
1587e5c31af7Sopenharmony_ci	for (int calcNdx = 0; calcNdx < FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS; calcNdx++)
1588e5c31af7Sopenharmony_ci	{
1589e5c31af7Sopenharmony_ci		if (calcNdx > 0)
1590e5c31af7Sopenharmony_ci			op << "\n";
1591e5c31af7Sopenharmony_ci
1592e5c31af7Sopenharmony_ci		op << "\t\t{\n";
1593e5c31af7Sopenharmony_ci
1594e5c31af7Sopenharmony_ci		for (int inputNdx = 0; inputNdx < numParams; inputNdx++)
1595e5c31af7Sopenharmony_ci		{
1596e5c31af7Sopenharmony_ci			const string inputName	= "in" + de::toString(calcNdx) + (char)('a'+inputNdx);
1597e5c31af7Sopenharmony_ci			const string incName	= string() + "u_inc" + (char)('A'+inputNdx);
1598e5c31af7Sopenharmony_ci			const string incExpr	= incrementExpr(incName, m_paramTypes[inputNdx], m_useNearlyConstantInputs);
1599e5c31af7Sopenharmony_ci
1600e5c31af7Sopenharmony_ci			op << "\t\t\t" << inputName << " = " << sumExpr(inputName, incExpr, m_paramTypes[inputNdx]) << ";\n";
1601e5c31af7Sopenharmony_ci		}
1602e5c31af7Sopenharmony_ci
1603e5c31af7Sopenharmony_ci		op << "\t\t\t" << returnPrecisionMaybe << returnTypeName << " eval" << calcNdx << " = ";
1604e5c31af7Sopenharmony_ci
1605e5c31af7Sopenharmony_ci		if (programID == PROGRAM_WITH_FUNCTION_CALLS)
1606e5c31af7Sopenharmony_ci		{
1607e5c31af7Sopenharmony_ci			op << m_func << "(";
1608e5c31af7Sopenharmony_ci
1609e5c31af7Sopenharmony_ci			for (int paramNdx = 0; paramNdx < numParams; paramNdx++)
1610e5c31af7Sopenharmony_ci			{
1611e5c31af7Sopenharmony_ci				if (paramNdx > 0)
1612e5c31af7Sopenharmony_ci					op << ", ";
1613e5c31af7Sopenharmony_ci
1614e5c31af7Sopenharmony_ci				op << "in" << calcNdx << (char)('a'+paramNdx);
1615e5c31af7Sopenharmony_ci			}
1616e5c31af7Sopenharmony_ci
1617e5c31af7Sopenharmony_ci			op << ")";
1618e5c31af7Sopenharmony_ci		}
1619e5c31af7Sopenharmony_ci		else
1620e5c31af7Sopenharmony_ci		{
1621e5c31af7Sopenharmony_ci			DE_ASSERT(programID == PROGRAM_WITHOUT_FUNCTION_CALLS);
1622e5c31af7Sopenharmony_ci			op << returnTypeName << "(1)";
1623e5c31af7Sopenharmony_ci		}
1624e5c31af7Sopenharmony_ci
1625e5c31af7Sopenharmony_ci		op << ";\n";
1626e5c31af7Sopenharmony_ci
1627e5c31af7Sopenharmony_ci		{
1628e5c31af7Sopenharmony_ci			const string resName	= "res" + de::toString(calcNdx);
1629e5c31af7Sopenharmony_ci			const string evalName	= "eval" + de::toString(calcNdx);
1630e5c31af7Sopenharmony_ci			const string incExpr	= incrementExpr(evalName, m_returnType, m_useNearlyConstantInputs);
1631e5c31af7Sopenharmony_ci
1632e5c31af7Sopenharmony_ci			op << "\t\t\tres" << calcNdx << " = " << sumExpr(resName, incExpr, m_returnType) << ";\n";
1633e5c31af7Sopenharmony_ci		}
1634e5c31af7Sopenharmony_ci
1635e5c31af7Sopenharmony_ci		op << "\t\t}\n";
1636e5c31af7Sopenharmony_ci	}
1637e5c31af7Sopenharmony_ci	op << "\t}\n";
1638e5c31af7Sopenharmony_ci	op << "\n";
1639e5c31af7Sopenharmony_ci
1640e5c31af7Sopenharmony_ci	// Result variables.
1641e5c31af7Sopenharmony_ci	for (int inputNdx = 0; inputNdx < numParams; inputNdx++)
1642e5c31af7Sopenharmony_ci	{
1643e5c31af7Sopenharmony_ci		op << "\t" << paramPrecisionsMaybe[inputNdx] << paramTypeNames[inputNdx] << " sumIn" << (char)('A'+inputNdx) << " = ";
1644e5c31af7Sopenharmony_ci		{
1645e5c31af7Sopenharmony_ci			string expr = string() + "in0" + (char)('a'+inputNdx);
1646e5c31af7Sopenharmony_ci			for (int i = 1; i < FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS; i++)
1647e5c31af7Sopenharmony_ci				expr = sumExpr(expr, string() + "in" + de::toString(i) + (char)('a'+inputNdx), m_paramTypes[inputNdx]);
1648e5c31af7Sopenharmony_ci			op << expr;
1649e5c31af7Sopenharmony_ci		}
1650e5c31af7Sopenharmony_ci		op << ";\n";
1651e5c31af7Sopenharmony_ci	}
1652e5c31af7Sopenharmony_ci
1653e5c31af7Sopenharmony_ci	op << "\t" << returnPrecisionMaybe << returnTypeName << " sumRes = ";
1654e5c31af7Sopenharmony_ci	{
1655e5c31af7Sopenharmony_ci		string expr = "res0";
1656e5c31af7Sopenharmony_ci		for (int i = 1; i < FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS; i++)
1657e5c31af7Sopenharmony_ci			expr = sumExpr(expr, "res" + de::toString(i), m_returnType);
1658e5c31af7Sopenharmony_ci		op << expr;
1659e5c31af7Sopenharmony_ci	}
1660e5c31af7Sopenharmony_ci	op << ";\n";
1661e5c31af7Sopenharmony_ci
1662e5c31af7Sopenharmony_ci	{
1663e5c31af7Sopenharmony_ci		glu::DataType finalResultDataType = glu::TYPE_LAST;
1664e5c31af7Sopenharmony_ci
1665e5c31af7Sopenharmony_ci		if (glu::isDataTypeMatrix(m_returnType))
1666e5c31af7Sopenharmony_ci		{
1667e5c31af7Sopenharmony_ci			finalResultDataType = m_returnType;
1668e5c31af7Sopenharmony_ci
1669e5c31af7Sopenharmony_ci			op << "\t" << precision << " " << returnTypeName << " finalRes = ";
1670e5c31af7Sopenharmony_ci
1671e5c31af7Sopenharmony_ci			for (int inputNdx = 0; inputNdx < numParams; inputNdx++)
1672e5c31af7Sopenharmony_ci			{
1673e5c31af7Sopenharmony_ci				DE_ASSERT(m_paramTypes[inputNdx] == m_returnType);
1674e5c31af7Sopenharmony_ci				op << "sumIn" << (char)('A'+inputNdx) << " + ";
1675e5c31af7Sopenharmony_ci			}
1676e5c31af7Sopenharmony_ci			op << "sumRes;\n";
1677e5c31af7Sopenharmony_ci		}
1678e5c31af7Sopenharmony_ci		else
1679e5c31af7Sopenharmony_ci		{
1680e5c31af7Sopenharmony_ci			int numFinalResComponents = glu::getDataTypeScalarSize(m_returnType);
1681e5c31af7Sopenharmony_ci			for (int inputNdx = 0; inputNdx < numParams; inputNdx++)
1682e5c31af7Sopenharmony_ci				numFinalResComponents = de::max(numFinalResComponents, glu::getDataTypeScalarSize(m_paramTypes[inputNdx]));
1683e5c31af7Sopenharmony_ci
1684e5c31af7Sopenharmony_ci			finalResultDataType = getDataTypeFloatOrVec(numFinalResComponents);
1685e5c31af7Sopenharmony_ci
1686e5c31af7Sopenharmony_ci			{
1687e5c31af7Sopenharmony_ci				const string finalResType = glu::getDataTypeName(finalResultDataType);
1688e5c31af7Sopenharmony_ci				op << "\t" << precision << " " << finalResType << " finalRes = ";
1689e5c31af7Sopenharmony_ci				for (int inputNdx = 0; inputNdx < numParams; inputNdx++)
1690e5c31af7Sopenharmony_ci					op << finalResType << "(sumIn" << (char)('A'+inputNdx) << ") + ";
1691e5c31af7Sopenharmony_ci				op << finalResType << "(sumRes);\n";
1692e5c31af7Sopenharmony_ci			}
1693e5c31af7Sopenharmony_ci		}
1694e5c31af7Sopenharmony_ci
1695e5c31af7Sopenharmony_ci		// Convert to color.
1696e5c31af7Sopenharmony_ci		op << "\tmediump vec4 color = ";
1697e5c31af7Sopenharmony_ci		if (finalResultDataType == TYPE_FLOAT_VEC4)
1698e5c31af7Sopenharmony_ci			op << "finalRes";
1699e5c31af7Sopenharmony_ci		else
1700e5c31af7Sopenharmony_ci		{
1701e5c31af7Sopenharmony_ci			int size = isMatrixReturn ? getDataTypeMatrixNumRows(finalResultDataType) : getDataTypeScalarSize(finalResultDataType);
1702e5c31af7Sopenharmony_ci
1703e5c31af7Sopenharmony_ci			op << "vec4(";
1704e5c31af7Sopenharmony_ci
1705e5c31af7Sopenharmony_ci			if (isMatrixReturn)
1706e5c31af7Sopenharmony_ci			{
1707e5c31af7Sopenharmony_ci				for (int i = 0; i < getDataTypeMatrixNumColumns(finalResultDataType); i++)
1708e5c31af7Sopenharmony_ci				{
1709e5c31af7Sopenharmony_ci					if (i > 0)
1710e5c31af7Sopenharmony_ci						op << " + ";
1711e5c31af7Sopenharmony_ci					op << "finalRes[" << i << "]";
1712e5c31af7Sopenharmony_ci				}
1713e5c31af7Sopenharmony_ci			}
1714e5c31af7Sopenharmony_ci			else
1715e5c31af7Sopenharmony_ci				op << "finalRes";
1716e5c31af7Sopenharmony_ci
1717e5c31af7Sopenharmony_ci			for (int i = size; i < 4; i++)
1718e5c31af7Sopenharmony_ci				op << ", " << (i == 3 ? "1.0" : "0.0");
1719e5c31af7Sopenharmony_ci
1720e5c31af7Sopenharmony_ci			op << ")";
1721e5c31af7Sopenharmony_ci		}
1722e5c31af7Sopenharmony_ci		op << ";\n";
1723e5c31af7Sopenharmony_ci		op << "\t" << (isVertexCase ? "v_color" : "gl_FragColor") << " = color;\n";
1724e5c31af7Sopenharmony_ci
1725e5c31af7Sopenharmony_ci		if (isVertexCase)
1726e5c31af7Sopenharmony_ci		{
1727e5c31af7Sopenharmony_ci			vtx << "	gl_Position = a_position + u_zero*color;\n";
1728e5c31af7Sopenharmony_ci			frag << "	gl_FragColor = v_color;\n";
1729e5c31af7Sopenharmony_ci		}
1730e5c31af7Sopenharmony_ci		else
1731e5c31af7Sopenharmony_ci		{
1732e5c31af7Sopenharmony_ci			for (int i = 0; i < numAttributes; i++)
1733e5c31af7Sopenharmony_ci				vtx << "	v_in" << i << " = a_in" << i << ";\n";
1734e5c31af7Sopenharmony_ci		}
1735e5c31af7Sopenharmony_ci
1736e5c31af7Sopenharmony_ci		vtx << "}\n";
1737e5c31af7Sopenharmony_ci		frag << "}\n";
1738e5c31af7Sopenharmony_ci	}
1739e5c31af7Sopenharmony_ci
1740e5c31af7Sopenharmony_ci	{
1741e5c31af7Sopenharmony_ci		vector<AttribSpec> attributes;
1742e5c31af7Sopenharmony_ci		for (int i = 0; i < numAttributes; i++)
1743e5c31af7Sopenharmony_ci			attributes.push_back(AttribSpec(("a_in" + de::toString(i)).c_str(),
1744e5c31af7Sopenharmony_ci											m_attribute.swizzle((i+0)%4, (i+1)%4, (i+2)%4, (i+3)%4),
1745e5c31af7Sopenharmony_ci											m_attribute.swizzle((i+1)%4, (i+2)%4, (i+3)%4, (i+0)%4),
1746e5c31af7Sopenharmony_ci											m_attribute.swizzle((i+2)%4, (i+3)%4, (i+0)%4, (i+1)%4),
1747e5c31af7Sopenharmony_ci											m_attribute.swizzle((i+3)%4, (i+0)%4, (i+1)%4, (i+2)%4)));
1748e5c31af7Sopenharmony_ci
1749e5c31af7Sopenharmony_ci		{
1750e5c31af7Sopenharmony_ci			string description = "This is the program ";
1751e5c31af7Sopenharmony_ci
1752e5c31af7Sopenharmony_ci			description += programID == PROGRAM_WITHOUT_FUNCTION_CALLS	? "without"
1753e5c31af7Sopenharmony_ci						 : programID == PROGRAM_WITH_FUNCTION_CALLS		? "with"
1754e5c31af7Sopenharmony_ci						 : DE_NULL;
1755e5c31af7Sopenharmony_ci
1756e5c31af7Sopenharmony_ci			description += " '" + m_func + "' function calls.\n"
1757e5c31af7Sopenharmony_ci						   "Note: workload size for this program means the number of loop iterations.";
1758e5c31af7Sopenharmony_ci
1759e5c31af7Sopenharmony_ci			return ProgramContext(vtx.str(), frag.str(), attributes, description);
1760e5c31af7Sopenharmony_ci		}
1761e5c31af7Sopenharmony_ci	}
1762e5c31af7Sopenharmony_ci}
1763e5c31af7Sopenharmony_ci
1764e5c31af7Sopenharmony_civector<FunctionCase::ProgramContext> FunctionCase::generateProgramData (void) const
1765e5c31af7Sopenharmony_ci{
1766e5c31af7Sopenharmony_ci	vector<ProgramContext> progData;
1767e5c31af7Sopenharmony_ci	for (int i = 0; i < PROGRAM_LAST; i++)
1768e5c31af7Sopenharmony_ci		progData.push_back(generateSingleProgramData((ProgramID)i));
1769e5c31af7Sopenharmony_ci	return progData;
1770e5c31af7Sopenharmony_ci}
1771e5c31af7Sopenharmony_ci
1772e5c31af7Sopenharmony_civoid FunctionCase::setGeneralUniforms (deUint32 program) const
1773e5c31af7Sopenharmony_ci{
1774e5c31af7Sopenharmony_ci	const glw::Functions& gl = m_renderCtx.getFunctions();
1775e5c31af7Sopenharmony_ci
1776e5c31af7Sopenharmony_ci	gl.uniform1f(gl.getUniformLocation(program, "u_zero"), 0.0f);
1777e5c31af7Sopenharmony_ci
1778e5c31af7Sopenharmony_ci	for (int paramNdx = 0; paramNdx < MAX_PARAMS; paramNdx++)
1779e5c31af7Sopenharmony_ci	{
1780e5c31af7Sopenharmony_ci		if (m_paramTypes[paramNdx] != glu::TYPE_INVALID)
1781e5c31af7Sopenharmony_ci		{
1782e5c31af7Sopenharmony_ci			const glu::DataType		paramType	= m_paramTypes[paramNdx];
1783e5c31af7Sopenharmony_ci			const int				scalarSize	= glu::getDataTypeScalarSize(paramType);
1784e5c31af7Sopenharmony_ci			const int				location	= gl.getUniformLocation(program, (string() + "u_inc" + (char)('A'+paramNdx)).c_str());
1785e5c31af7Sopenharmony_ci
1786e5c31af7Sopenharmony_ci			if (glu::isDataTypeFloatOrVec(paramType))
1787e5c31af7Sopenharmony_ci			{
1788e5c31af7Sopenharmony_ci				float values[4];
1789e5c31af7Sopenharmony_ci				for (int i = 0; i < DE_LENGTH_OF_ARRAY(values); i++)
1790e5c31af7Sopenharmony_ci					values[i] = (float)paramNdx*0.01f + (float)i*0.001f; // Arbitrary small values.
1791e5c31af7Sopenharmony_ci				uniformNfv(gl, scalarSize, location, 1, &values[0]);
1792e5c31af7Sopenharmony_ci			}
1793e5c31af7Sopenharmony_ci			else if (glu::isDataTypeIntOrIVec(paramType))
1794e5c31af7Sopenharmony_ci			{
1795e5c31af7Sopenharmony_ci				int values[4];
1796e5c31af7Sopenharmony_ci				for (int i = 0; i < DE_LENGTH_OF_ARRAY(values); i++)
1797e5c31af7Sopenharmony_ci					values[i] = paramNdx*100 + i; // Arbitrary values.
1798e5c31af7Sopenharmony_ci				uniformNiv(gl, scalarSize, location, 1, &values[0]);
1799e5c31af7Sopenharmony_ci			}
1800e5c31af7Sopenharmony_ci			else if (glu::isDataTypeBoolOrBVec(paramType))
1801e5c31af7Sopenharmony_ci			{
1802e5c31af7Sopenharmony_ci				int values[4];
1803e5c31af7Sopenharmony_ci				for (int i = 0; i < DE_LENGTH_OF_ARRAY(values); i++)
1804e5c31af7Sopenharmony_ci					values[i] = (paramNdx >> i) & 1; // Arbitrary values.
1805e5c31af7Sopenharmony_ci				uniformNiv(gl, scalarSize, location, 1, &values[0]);
1806e5c31af7Sopenharmony_ci			}
1807e5c31af7Sopenharmony_ci			else if (glu::isDataTypeMatrix(paramType))
1808e5c31af7Sopenharmony_ci			{
1809e5c31af7Sopenharmony_ci				const int size = glu::getDataTypeMatrixNumRows(paramType);
1810e5c31af7Sopenharmony_ci				DE_ASSERT(size == glu::getDataTypeMatrixNumColumns(paramType));
1811e5c31af7Sopenharmony_ci				float values[4*4];
1812e5c31af7Sopenharmony_ci				for (int i = 0; i < DE_LENGTH_OF_ARRAY(values); i++)
1813e5c31af7Sopenharmony_ci					values[i] = (float)paramNdx*0.01f + (float)i*0.001f; // Arbitrary values.
1814e5c31af7Sopenharmony_ci				uniformMatrixNfv(gl, size, location, 1, &values[0]);
1815e5c31af7Sopenharmony_ci			}
1816e5c31af7Sopenharmony_ci			else
1817e5c31af7Sopenharmony_ci				DE_ASSERT(false);
1818e5c31af7Sopenharmony_ci		}
1819e5c31af7Sopenharmony_ci	}
1820e5c31af7Sopenharmony_ci}
1821e5c31af7Sopenharmony_ci
1822e5c31af7Sopenharmony_civoid FunctionCase::setWorkloadSizeUniform (deUint32 program, int numLoopIterations) const
1823e5c31af7Sopenharmony_ci{
1824e5c31af7Sopenharmony_ci	const glw::Functions&	gl		= m_renderCtx.getFunctions();
1825e5c31af7Sopenharmony_ci	const int				loc		= gl.getUniformLocation(program, "u_numLoopIterations");
1826e5c31af7Sopenharmony_ci
1827e5c31af7Sopenharmony_ci	gl.uniform1i(loc, numLoopIterations);
1828e5c31af7Sopenharmony_ci}
1829e5c31af7Sopenharmony_ci
1830e5c31af7Sopenharmony_cifloat FunctionCase::computeSingleOperationTime (const vector<float>& perProgramOperationCosts) const
1831e5c31af7Sopenharmony_ci{
1832e5c31af7Sopenharmony_ci	DE_ASSERT(perProgramOperationCosts.size() == PROGRAM_LAST);
1833e5c31af7Sopenharmony_ci	const int		numFunctionCalls			= FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS;
1834e5c31af7Sopenharmony_ci	const float		programOperationCostDiff	= perProgramOperationCosts[PROGRAM_WITH_FUNCTION_CALLS] - perProgramOperationCosts[PROGRAM_WITHOUT_FUNCTION_CALLS];
1835e5c31af7Sopenharmony_ci
1836e5c31af7Sopenharmony_ci	return programOperationCostDiff / (float)numFunctionCalls;
1837e5c31af7Sopenharmony_ci}
1838e5c31af7Sopenharmony_ci
1839e5c31af7Sopenharmony_civoid FunctionCase::logSingleOperationCalculationInfo (void) const
1840e5c31af7Sopenharmony_ci{
1841e5c31af7Sopenharmony_ci	const int numFunctionCalls = FUNCTION_CASE_NUM_INDEPENDENT_CALCULATIONS;
1842e5c31af7Sopenharmony_ci
1843e5c31af7Sopenharmony_ci	m_testCtx.getLog() << TestLog::Message << "Note: program " << (int)PROGRAM_WITH_FUNCTION_CALLS << " contains "
1844e5c31af7Sopenharmony_ci										   << numFunctionCalls << " calls to '" << m_func << "' in one loop iteration; "
1845e5c31af7Sopenharmony_ci										   << "cost of one operation is calculated as "
1846e5c31af7Sopenharmony_ci										   << "(cost_of_workload_with_calls - cost_of_workload_without_calls) / " << numFunctionCalls << TestLog::EndMessage;
1847e5c31af7Sopenharmony_ci}
1848e5c31af7Sopenharmony_ci
1849e5c31af7Sopenharmony_ci} // anonymous
1850e5c31af7Sopenharmony_ci
1851e5c31af7Sopenharmony_ciShaderOperatorTests::ShaderOperatorTests (Context& context)
1852e5c31af7Sopenharmony_ci	: TestCaseGroup(context, "operator", "Operator Performance Tests")
1853e5c31af7Sopenharmony_ci{
1854e5c31af7Sopenharmony_ci}
1855e5c31af7Sopenharmony_ci
1856e5c31af7Sopenharmony_ciShaderOperatorTests::~ShaderOperatorTests (void)
1857e5c31af7Sopenharmony_ci{
1858e5c31af7Sopenharmony_ci}
1859e5c31af7Sopenharmony_ci
1860e5c31af7Sopenharmony_civoid ShaderOperatorTests::init (void)
1861e5c31af7Sopenharmony_ci{
1862e5c31af7Sopenharmony_ci	// Binary operator cases
1863e5c31af7Sopenharmony_ci
1864e5c31af7Sopenharmony_ci	static const DataType binaryOpTypes[] =
1865e5c31af7Sopenharmony_ci	{
1866e5c31af7Sopenharmony_ci		TYPE_FLOAT,
1867e5c31af7Sopenharmony_ci		TYPE_FLOAT_VEC2,
1868e5c31af7Sopenharmony_ci		TYPE_FLOAT_VEC3,
1869e5c31af7Sopenharmony_ci		TYPE_FLOAT_VEC4,
1870e5c31af7Sopenharmony_ci		TYPE_INT,
1871e5c31af7Sopenharmony_ci		TYPE_INT_VEC2,
1872e5c31af7Sopenharmony_ci		TYPE_INT_VEC3,
1873e5c31af7Sopenharmony_ci		TYPE_INT_VEC4,
1874e5c31af7Sopenharmony_ci	};
1875e5c31af7Sopenharmony_ci	static const Precision precisions[] =
1876e5c31af7Sopenharmony_ci	{
1877e5c31af7Sopenharmony_ci		PRECISION_LOWP,
1878e5c31af7Sopenharmony_ci		PRECISION_MEDIUMP,
1879e5c31af7Sopenharmony_ci		PRECISION_HIGHP
1880e5c31af7Sopenharmony_ci	};
1881e5c31af7Sopenharmony_ci	static const struct
1882e5c31af7Sopenharmony_ci	{
1883e5c31af7Sopenharmony_ci		const char*		name;
1884e5c31af7Sopenharmony_ci		const char*		op;
1885e5c31af7Sopenharmony_ci		bool			swizzle;
1886e5c31af7Sopenharmony_ci	} binaryOps[] =
1887e5c31af7Sopenharmony_ci	{
1888e5c31af7Sopenharmony_ci		{ "add",		"+",		false	},
1889e5c31af7Sopenharmony_ci		{ "sub",		"-",		true	},
1890e5c31af7Sopenharmony_ci		{ "mul",		"*",		false	},
1891e5c31af7Sopenharmony_ci		{ "div",		"/",		true	}
1892e5c31af7Sopenharmony_ci	};
1893e5c31af7Sopenharmony_ci
1894e5c31af7Sopenharmony_ci	tcu::TestCaseGroup* const binaryOpsGroup = new tcu::TestCaseGroup(m_testCtx, "binary_operator", "Binary Operator Performance Tests");
1895e5c31af7Sopenharmony_ci	addChild(binaryOpsGroup);
1896e5c31af7Sopenharmony_ci
1897e5c31af7Sopenharmony_ci	for (int opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(binaryOps); opNdx++)
1898e5c31af7Sopenharmony_ci	{
1899e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* const opGroup = new tcu::TestCaseGroup(m_testCtx, binaryOps[opNdx].name, "");
1900e5c31af7Sopenharmony_ci		binaryOpsGroup->addChild(opGroup);
1901e5c31af7Sopenharmony_ci
1902e5c31af7Sopenharmony_ci		for (int isFrag = 0; isFrag <= 1; isFrag++)
1903e5c31af7Sopenharmony_ci		{
1904e5c31af7Sopenharmony_ci			const BinaryOpCase::InitialCalibrationStorage	shaderGroupCalibrationStorage	(new BinaryOpCase::InitialCalibration);
1905e5c31af7Sopenharmony_ci			const bool										isVertex						= isFrag == 0;
1906e5c31af7Sopenharmony_ci			tcu::TestCaseGroup* const						shaderGroup						= new tcu::TestCaseGroup(m_testCtx, isVertex ? "vertex" : "fragment", "");
1907e5c31af7Sopenharmony_ci			opGroup->addChild(shaderGroup);
1908e5c31af7Sopenharmony_ci
1909e5c31af7Sopenharmony_ci			for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(binaryOpTypes); typeNdx++)
1910e5c31af7Sopenharmony_ci			{
1911e5c31af7Sopenharmony_ci				for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1912e5c31af7Sopenharmony_ci				{
1913e5c31af7Sopenharmony_ci					const DataType		type			= binaryOpTypes[typeNdx];
1914e5c31af7Sopenharmony_ci					const Precision		precision		= precisions[precNdx];
1915e5c31af7Sopenharmony_ci					const char* const	op				= binaryOps[opNdx].op;
1916e5c31af7Sopenharmony_ci					const bool			useSwizzle		= binaryOps[opNdx].swizzle;
1917e5c31af7Sopenharmony_ci					std::ostringstream	name;
1918e5c31af7Sopenharmony_ci
1919e5c31af7Sopenharmony_ci					name << getPrecisionName(precision) << "_" << getDataTypeName(type);
1920e5c31af7Sopenharmony_ci
1921e5c31af7Sopenharmony_ci					shaderGroup->addChild(new BinaryOpCase(m_context, name.str().c_str(), "", op, type, precision, useSwizzle, isVertex, shaderGroupCalibrationStorage));
1922e5c31af7Sopenharmony_ci				}
1923e5c31af7Sopenharmony_ci			}
1924e5c31af7Sopenharmony_ci		}
1925e5c31af7Sopenharmony_ci	}
1926e5c31af7Sopenharmony_ci
1927e5c31af7Sopenharmony_ci	// Built-in function cases.
1928e5c31af7Sopenharmony_ci
1929e5c31af7Sopenharmony_ci	// Non-specific (i.e. includes gentypes) parameter types for the functions.
1930e5c31af7Sopenharmony_ci	enum ValueType
1931e5c31af7Sopenharmony_ci	{
1932e5c31af7Sopenharmony_ci		VALUE_NONE			= 0,
1933e5c31af7Sopenharmony_ci		VALUE_FLOAT			= (1<<0),	// float scalar
1934e5c31af7Sopenharmony_ci		VALUE_FLOAT_VEC		= (1<<1),	// float vector
1935e5c31af7Sopenharmony_ci		VALUE_FLOAT_VEC34	= (1<<2),	// float vector of size 3 or 4
1936e5c31af7Sopenharmony_ci		VALUE_FLOAT_GENTYPE	= (1<<3),	// float scalar/vector
1937e5c31af7Sopenharmony_ci		VALUE_VEC3			= (1<<4),	// vec3 only
1938e5c31af7Sopenharmony_ci		VALUE_VEC4			= (1<<5),	// vec4 only
1939e5c31af7Sopenharmony_ci		VALUE_MATRIX		= (1<<6),	// matrix
1940e5c31af7Sopenharmony_ci		VALUE_BOOL			= (1<<7),	// boolean scalar
1941e5c31af7Sopenharmony_ci		VALUE_BOOL_VEC		= (1<<8),	// boolean vector
1942e5c31af7Sopenharmony_ci		VALUE_BOOL_GENTYPE	= (1<<9),	// boolean scalar/vector
1943e5c31af7Sopenharmony_ci		VALUE_INT			= (1<<10),	// int scalar
1944e5c31af7Sopenharmony_ci		VALUE_INT_VEC		= (1<<11),	// int vector
1945e5c31af7Sopenharmony_ci		VALUE_INT_GENTYPE	= (1<<12),	// int scalar/vector
1946e5c31af7Sopenharmony_ci
1947e5c31af7Sopenharmony_ci		// Shorthands.
1948e5c31af7Sopenharmony_ci		N				= VALUE_NONE,
1949e5c31af7Sopenharmony_ci		F				= VALUE_FLOAT,
1950e5c31af7Sopenharmony_ci		FV				= VALUE_FLOAT_VEC,
1951e5c31af7Sopenharmony_ci		VL				= VALUE_FLOAT_VEC34, // L for "large"
1952e5c31af7Sopenharmony_ci		GT				= VALUE_FLOAT_GENTYPE,
1953e5c31af7Sopenharmony_ci		V3				= VALUE_VEC3,
1954e5c31af7Sopenharmony_ci		V4				= VALUE_VEC4,
1955e5c31af7Sopenharmony_ci		M				= VALUE_MATRIX,
1956e5c31af7Sopenharmony_ci		B				= VALUE_BOOL,
1957e5c31af7Sopenharmony_ci		BV				= VALUE_BOOL_VEC,
1958e5c31af7Sopenharmony_ci		BGT				= VALUE_BOOL_GENTYPE,
1959e5c31af7Sopenharmony_ci		I				= VALUE_INT,
1960e5c31af7Sopenharmony_ci		IV				= VALUE_INT_VEC,
1961e5c31af7Sopenharmony_ci		IGT				= VALUE_INT_GENTYPE,
1962e5c31af7Sopenharmony_ci
1963e5c31af7Sopenharmony_ci		VALUE_ANY_FLOAT			= VALUE_FLOAT		|	VALUE_FLOAT_VEC		|	VALUE_FLOAT_GENTYPE	| VALUE_VEC3 | VALUE_VEC4 | VALUE_FLOAT_VEC34,
1964e5c31af7Sopenharmony_ci		VALUE_ANY_INT			= VALUE_INT			|	VALUE_INT_VEC		|	VALUE_INT_GENTYPE,
1965e5c31af7Sopenharmony_ci		VALUE_ANY_BOOL			= VALUE_BOOL		|	VALUE_BOOL_VEC		|	VALUE_BOOL_GENTYPE,
1966e5c31af7Sopenharmony_ci
1967e5c31af7Sopenharmony_ci		VALUE_ANY_GENTYPE		= VALUE_FLOAT_VEC	|	VALUE_FLOAT_GENTYPE	|	VALUE_FLOAT_VEC34	|
1968e5c31af7Sopenharmony_ci								  VALUE_BOOL_VEC	|	VALUE_BOOL_GENTYPE	|
1969e5c31af7Sopenharmony_ci								  VALUE_INT_VEC		|	VALUE_INT_GENTYPE	|
1970e5c31af7Sopenharmony_ci								  VALUE_MATRIX
1971e5c31af7Sopenharmony_ci	};
1972e5c31af7Sopenharmony_ci	enum PrecisionMask
1973e5c31af7Sopenharmony_ci	{
1974e5c31af7Sopenharmony_ci		PRECMASK_NA				= 0,						//!< Precision not applicable (booleans)
1975e5c31af7Sopenharmony_ci		PRECMASK_LOWP			= (1<<PRECISION_LOWP),
1976e5c31af7Sopenharmony_ci		PRECMASK_MEDIUMP		= (1<<PRECISION_MEDIUMP),
1977e5c31af7Sopenharmony_ci		PRECMASK_HIGHP			= (1<<PRECISION_HIGHP),
1978e5c31af7Sopenharmony_ci
1979e5c31af7Sopenharmony_ci		PRECMASK_MEDIUMP_HIGHP	= (1<<PRECISION_MEDIUMP) | (1<<PRECISION_HIGHP),
1980e5c31af7Sopenharmony_ci		PRECMASK_ALL			= (1<<PRECISION_LOWP) | (1<<PRECISION_MEDIUMP) | (1<<PRECISION_HIGHP)
1981e5c31af7Sopenharmony_ci	};
1982e5c31af7Sopenharmony_ci
1983e5c31af7Sopenharmony_ci	static const DataType floatTypes[] =
1984e5c31af7Sopenharmony_ci	{
1985e5c31af7Sopenharmony_ci		TYPE_FLOAT,
1986e5c31af7Sopenharmony_ci		TYPE_FLOAT_VEC2,
1987e5c31af7Sopenharmony_ci		TYPE_FLOAT_VEC3,
1988e5c31af7Sopenharmony_ci		TYPE_FLOAT_VEC4
1989e5c31af7Sopenharmony_ci	};
1990e5c31af7Sopenharmony_ci	static const DataType intTypes[] =
1991e5c31af7Sopenharmony_ci	{
1992e5c31af7Sopenharmony_ci		TYPE_INT,
1993e5c31af7Sopenharmony_ci		TYPE_INT_VEC2,
1994e5c31af7Sopenharmony_ci		TYPE_INT_VEC3,
1995e5c31af7Sopenharmony_ci		TYPE_INT_VEC4
1996e5c31af7Sopenharmony_ci	};
1997e5c31af7Sopenharmony_ci	static const DataType boolTypes[] =
1998e5c31af7Sopenharmony_ci	{
1999e5c31af7Sopenharmony_ci		TYPE_BOOL,
2000e5c31af7Sopenharmony_ci		TYPE_BOOL_VEC2,
2001e5c31af7Sopenharmony_ci		TYPE_BOOL_VEC3,
2002e5c31af7Sopenharmony_ci		TYPE_BOOL_VEC4
2003e5c31af7Sopenharmony_ci	};
2004e5c31af7Sopenharmony_ci	static const DataType matrixTypes[] =
2005e5c31af7Sopenharmony_ci	{
2006e5c31af7Sopenharmony_ci		TYPE_FLOAT_MAT2,
2007e5c31af7Sopenharmony_ci		TYPE_FLOAT_MAT3,
2008e5c31af7Sopenharmony_ci		TYPE_FLOAT_MAT4
2009e5c31af7Sopenharmony_ci	};
2010e5c31af7Sopenharmony_ci
2011e5c31af7Sopenharmony_ci	tcu::TestCaseGroup* const angleAndTrigonometryGroup		= new tcu::TestCaseGroup(m_testCtx, "angle_and_trigonometry",	"Built-In Angle and Trigonometry Function Performance Tests");
2012e5c31af7Sopenharmony_ci	tcu::TestCaseGroup* const exponentialGroup				= new tcu::TestCaseGroup(m_testCtx, "exponential",				"Built-In Exponential Function Performance Tests");
2013e5c31af7Sopenharmony_ci	tcu::TestCaseGroup* const commonFunctionsGroup			= new tcu::TestCaseGroup(m_testCtx, "common_functions",			"Built-In Common Function Performance Tests");
2014e5c31af7Sopenharmony_ci	tcu::TestCaseGroup* const geometricFunctionsGroup		= new tcu::TestCaseGroup(m_testCtx, "geometric",				"Built-In Geometric Function Performance Tests");
2015e5c31af7Sopenharmony_ci	tcu::TestCaseGroup* const matrixFunctionsGroup			= new tcu::TestCaseGroup(m_testCtx, "matrix",					"Built-In Matrix Function Performance Tests");
2016e5c31af7Sopenharmony_ci	tcu::TestCaseGroup* const floatCompareGroup				= new tcu::TestCaseGroup(m_testCtx, "float_compare",			"Built-In Floating Point Comparison Function Performance Tests");
2017e5c31af7Sopenharmony_ci	tcu::TestCaseGroup* const intCompareGroup				= new tcu::TestCaseGroup(m_testCtx, "int_compare",				"Built-In Integer Comparison Function Performance Tests");
2018e5c31af7Sopenharmony_ci	tcu::TestCaseGroup* const boolCompareGroup				= new tcu::TestCaseGroup(m_testCtx, "bool_compare",				"Built-In Boolean Comparison Function Performance Tests");
2019e5c31af7Sopenharmony_ci
2020e5c31af7Sopenharmony_ci	addChild(angleAndTrigonometryGroup);
2021e5c31af7Sopenharmony_ci	addChild(exponentialGroup);
2022e5c31af7Sopenharmony_ci	addChild(commonFunctionsGroup);
2023e5c31af7Sopenharmony_ci	addChild(geometricFunctionsGroup);
2024e5c31af7Sopenharmony_ci	addChild(matrixFunctionsGroup);
2025e5c31af7Sopenharmony_ci	addChild(floatCompareGroup);
2026e5c31af7Sopenharmony_ci	addChild(intCompareGroup);
2027e5c31af7Sopenharmony_ci	addChild(boolCompareGroup);
2028e5c31af7Sopenharmony_ci
2029e5c31af7Sopenharmony_ci	// Some attributes to be used as parameters for the functions.
2030e5c31af7Sopenharmony_ci	const Vec4 attrPos		= Vec4( 2.3f,  1.9f,  0.8f,  0.7f);
2031e5c31af7Sopenharmony_ci	const Vec4 attrNegPos	= Vec4(-1.3f,  2.5f, -3.5f,	 4.3f);
2032e5c31af7Sopenharmony_ci	const Vec4 attrSmall	= Vec4(-0.9f,  0.8f, -0.4f,	 0.2f);
2033e5c31af7Sopenharmony_ci
2034e5c31af7Sopenharmony_ci	// Function name, return type and parameter type information; also, what attribute should be used in the test.
2035e5c31af7Sopenharmony_ci	// \note Different versions of the same function (i.e. with the same group name) can be defined by putting them successively in this array.
2036e5c31af7Sopenharmony_ci	// \note In order to reduce case count and thus total execution time, we don't test all input type combinations for every function.
2037e5c31af7Sopenharmony_ci	static const struct
2038e5c31af7Sopenharmony_ci	{
2039e5c31af7Sopenharmony_ci		tcu::TestCaseGroup*					parentGroup;
2040e5c31af7Sopenharmony_ci		const char*							groupName;
2041e5c31af7Sopenharmony_ci		const char*							func;
2042e5c31af7Sopenharmony_ci		const ValueType						types[FunctionCase::MAX_PARAMS + 1]; // Return type and parameter types, in that order.
2043e5c31af7Sopenharmony_ci		const Vec4&							attribute;
2044e5c31af7Sopenharmony_ci		int									modifyParamNdx;
2045e5c31af7Sopenharmony_ci		bool								useNearlyConstantInputs;
2046e5c31af7Sopenharmony_ci		bool								booleanCase;
2047e5c31af7Sopenharmony_ci		PrecisionMask						precMask;
2048e5c31af7Sopenharmony_ci	} functionCaseGroups[] =
2049e5c31af7Sopenharmony_ci	{
2050e5c31af7Sopenharmony_ci		{ angleAndTrigonometryGroup,	"radians",			"radians",			{ F,  F,  N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2051e5c31af7Sopenharmony_ci		{ angleAndTrigonometryGroup,	"degrees",			"degrees",			{ F,  F,  N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2052e5c31af7Sopenharmony_ci		{ angleAndTrigonometryGroup,	"sin",				"sin",				{ F,  F,  N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2053e5c31af7Sopenharmony_ci		{ angleAndTrigonometryGroup,	"cos",				"cos",				{ F,  F,  N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2054e5c31af7Sopenharmony_ci		{ angleAndTrigonometryGroup,	"tan",				"tan",				{ F,  F,  N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2055e5c31af7Sopenharmony_ci		{ angleAndTrigonometryGroup,	"asin",				"asin",				{ F,  F,  N,  N  }, attrSmall,		-1, true,	false,	PRECMASK_ALL			},
2056e5c31af7Sopenharmony_ci		{ angleAndTrigonometryGroup,	"acos",				"acos",				{ F,  F,  N,  N  }, attrSmall,		-1, true,	false,	PRECMASK_ALL			},
2057e5c31af7Sopenharmony_ci		{ angleAndTrigonometryGroup,	"atan2",			"atan",				{ F,  F,  F,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2058e5c31af7Sopenharmony_ci		{ angleAndTrigonometryGroup,	"atan",				"atan",				{ F,  F,  N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2059e5c31af7Sopenharmony_ci
2060e5c31af7Sopenharmony_ci		{ exponentialGroup,				"pow",				"pow",				{ F,  F,  F,  N  }, attrPos,		-1, false,	false,	PRECMASK_ALL			},
2061e5c31af7Sopenharmony_ci		{ exponentialGroup,				"exp",				"exp",				{ F,  F,  N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2062e5c31af7Sopenharmony_ci		{ exponentialGroup,				"log",				"log",				{ F,  F,  N,  N  }, attrPos,		-1, false,	false,	PRECMASK_ALL			},
2063e5c31af7Sopenharmony_ci		{ exponentialGroup,				"exp2",				"exp2",				{ F,  F,  N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2064e5c31af7Sopenharmony_ci		{ exponentialGroup,				"log2",				"log2",				{ F,  F,  N,  N  }, attrPos,		-1, false,	false,	PRECMASK_ALL			},
2065e5c31af7Sopenharmony_ci		{ exponentialGroup,				"sqrt",				"sqrt",				{ F,  F,  N,  N  }, attrPos,		-1, false,	false,	PRECMASK_ALL			},
2066e5c31af7Sopenharmony_ci		{ exponentialGroup,				"inversesqrt",		"inversesqrt",		{ F,  F,  N,  N  }, attrPos,		-1, false,	false,	PRECMASK_ALL			},
2067e5c31af7Sopenharmony_ci
2068e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"abs",				"abs",				{ F,  F,  N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_MEDIUMP_HIGHP	},
2069e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"abs",				"abs",				{ V4, V4, N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2070e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"sign",				"sign",				{ F,  F,  N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_MEDIUMP_HIGHP	},
2071e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"sign",				"sign",				{ V4, V4, N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2072e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"floor",			"floor",			{ F,  F,  N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_MEDIUMP_HIGHP	},
2073e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"floor",			"floor",			{ V4, V4, N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2074e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"ceil",				"ceil",				{ F,  F,  N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_MEDIUMP_HIGHP	},
2075e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"ceil",				"ceil",				{ V4, V4, N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2076e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"fract",			"fract",			{ F,  F,  N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_MEDIUMP_HIGHP	},
2077e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"fract",			"fract",			{ V4, V4, N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2078e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"mod",				"mod",				{ GT, GT, GT, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2079e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"min",				"min",				{ F,  F,  F,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_MEDIUMP_HIGHP	},
2080e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"min",				"min",				{ V4, V4, V4, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2081e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"max",				"max",				{ F,  F,  F,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_MEDIUMP_HIGHP	},
2082e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"max",				"max",				{ V4, V4, V4, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2083e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"clamp",			"clamp",			{ F,  F,  F,  F  }, attrSmall,		 2, false,	false,	PRECMASK_MEDIUMP_HIGHP	},
2084e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"clamp",			"clamp",			{ V4, V4, V4, V4 }, attrSmall,		 2, false,	false,	PRECMASK_ALL			},
2085e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"mix",				"mix",				{ F,  F,  F,  F  }, attrNegPos,		-1, false,	false,	PRECMASK_MEDIUMP_HIGHP	},
2086e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"mix",				"mix",				{ V4, V4, V4, V4 }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2087e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"step",				"step",				{ F,  F,  F,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_MEDIUMP_HIGHP	},
2088e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"step",				"step",				{ V4, V4, V4, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2089e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"smoothstep",		"smoothstep",		{ F,  F,  F,  F  }, attrSmall,		 1, false,	false,	PRECMASK_MEDIUMP_HIGHP	},
2090e5c31af7Sopenharmony_ci		{ commonFunctionsGroup,			"smoothstep",		"smoothstep",		{ V4, V4, V4, V4 }, attrSmall,		 1, false,	false,	PRECMASK_ALL			},
2091e5c31af7Sopenharmony_ci
2092e5c31af7Sopenharmony_ci		{ geometricFunctionsGroup,		"length",			"length",			{ F,  VL, N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2093e5c31af7Sopenharmony_ci		{ geometricFunctionsGroup,		"distance",			"distance",			{ F,  VL, VL, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2094e5c31af7Sopenharmony_ci		{ geometricFunctionsGroup,		"dot",				"dot",				{ F,  VL, VL, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2095e5c31af7Sopenharmony_ci		{ geometricFunctionsGroup,		"cross",			"cross",			{ V3, V3, V3, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2096e5c31af7Sopenharmony_ci		{ geometricFunctionsGroup,		"normalize",		"normalize",		{ VL, VL, N,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2097e5c31af7Sopenharmony_ci		{ geometricFunctionsGroup,		"faceforward",		"faceforward",		{ VL, VL, VL, VL }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2098e5c31af7Sopenharmony_ci		{ geometricFunctionsGroup,		"reflect",			"reflect",			{ VL, VL, VL, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2099e5c31af7Sopenharmony_ci		{ geometricFunctionsGroup,		"refract",			"refract",			{ VL, VL, VL, F  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2100e5c31af7Sopenharmony_ci
2101e5c31af7Sopenharmony_ci		{ matrixFunctionsGroup,			"matrixCompMult",	"matrixCompMult",	{ M,  M,  M,  N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2102e5c31af7Sopenharmony_ci
2103e5c31af7Sopenharmony_ci		{ floatCompareGroup,			"lessThan",			"lessThan",			{ BV, FV, FV, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2104e5c31af7Sopenharmony_ci		{ floatCompareGroup,			"lessThanEqual",	"lessThanEqual",	{ BV, FV, FV, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2105e5c31af7Sopenharmony_ci		{ floatCompareGroup,			"greaterThan",		"greaterThan",		{ BV, FV, FV, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2106e5c31af7Sopenharmony_ci		{ floatCompareGroup,			"greaterThanEqual",	"greaterThanEqual",	{ BV, FV, FV, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2107e5c31af7Sopenharmony_ci		{ floatCompareGroup,			"equal",			"equal",			{ BV, FV, FV, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2108e5c31af7Sopenharmony_ci		{ floatCompareGroup,			"notEqual",			"notEqual",			{ BV, FV, FV, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2109e5c31af7Sopenharmony_ci
2110e5c31af7Sopenharmony_ci		{ intCompareGroup,				"lessThan",			"lessThan",			{ BV, IV, IV, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2111e5c31af7Sopenharmony_ci		{ intCompareGroup,				"lessThanEqual",	"lessThanEqual",	{ BV, IV, IV, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2112e5c31af7Sopenharmony_ci		{ intCompareGroup,				"greaterThan",		"greaterThan",		{ BV, IV, IV, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2113e5c31af7Sopenharmony_ci		{ intCompareGroup,				"greaterThanEqual",	"greaterThanEqual",	{ BV, IV, IV, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2114e5c31af7Sopenharmony_ci		{ intCompareGroup,				"equal",			"equal",			{ BV, IV, IV, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2115e5c31af7Sopenharmony_ci		{ intCompareGroup,				"notEqual",			"notEqual",			{ BV, IV, IV, N  }, attrNegPos,		-1, false,	false,	PRECMASK_ALL			},
2116e5c31af7Sopenharmony_ci
2117e5c31af7Sopenharmony_ci		{ boolCompareGroup,				"equal",			"equal",			{ BV, BV, BV, N  }, attrNegPos,		-1, false,	true,	PRECMASK_MEDIUMP		},
2118e5c31af7Sopenharmony_ci		{ boolCompareGroup,				"notEqual",			"notEqual",			{ BV, BV, BV, N  }, attrNegPos,		-1, false,	true,	PRECMASK_MEDIUMP		},
2119e5c31af7Sopenharmony_ci		{ boolCompareGroup,				"any",				"any",				{ B,  BV, N,  N  }, attrNegPos,		-1, false,	true,	PRECMASK_MEDIUMP		},
2120e5c31af7Sopenharmony_ci		{ boolCompareGroup,				"all",				"all",				{ B,  BV, N,  N  }, attrNegPos,		-1, false,	true,	PRECMASK_MEDIUMP		},
2121e5c31af7Sopenharmony_ci		{ boolCompareGroup,				"not",				"not",				{ BV, BV, N,  N  }, attrNegPos,		-1, false,	true,	PRECMASK_MEDIUMP		}
2122e5c31af7Sopenharmony_ci	};
2123e5c31af7Sopenharmony_ci
2124e5c31af7Sopenharmony_ci	// vertexSubGroup and fragmentSubGroup are the groups where the various vertex/fragment cases of a single function are added.
2125e5c31af7Sopenharmony_ci	// \note These are defined here so that different versions (different entries in the functionCaseGroups array) of the same function can be put in the same group.
2126e5c31af7Sopenharmony_ci	tcu::TestCaseGroup*							vertexSubGroup		= DE_NULL;
2127e5c31af7Sopenharmony_ci	tcu::TestCaseGroup*							fragmentSubGroup	= DE_NULL;
2128e5c31af7Sopenharmony_ci	FunctionCase::InitialCalibrationStorage		vertexSubGroupCalibrationStorage;
2129e5c31af7Sopenharmony_ci	FunctionCase::InitialCalibrationStorage		fragmentSubGroupCalibrationStorage;
2130e5c31af7Sopenharmony_ci	for (int funcNdx = 0; funcNdx < DE_LENGTH_OF_ARRAY(functionCaseGroups); funcNdx++)
2131e5c31af7Sopenharmony_ci	{
2132e5c31af7Sopenharmony_ci		tcu::TestCaseGroup* const	parentGroup					= functionCaseGroups[funcNdx].parentGroup;
2133e5c31af7Sopenharmony_ci		const char* const			groupName					= functionCaseGroups[funcNdx].groupName;
2134e5c31af7Sopenharmony_ci		const char* const			groupFunc					= functionCaseGroups[funcNdx].func;
2135e5c31af7Sopenharmony_ci		const ValueType* const		funcTypes					= functionCaseGroups[funcNdx].types;
2136e5c31af7Sopenharmony_ci		const Vec4&					groupAttribute				= functionCaseGroups[funcNdx].attribute;
2137e5c31af7Sopenharmony_ci		const int					modifyParamNdx				= functionCaseGroups[funcNdx].modifyParamNdx;
2138e5c31af7Sopenharmony_ci		const bool					useNearlyConstantInputs		= functionCaseGroups[funcNdx].useNearlyConstantInputs;
2139e5c31af7Sopenharmony_ci		const bool					booleanCase					= functionCaseGroups[funcNdx].booleanCase;
2140e5c31af7Sopenharmony_ci		const PrecisionMask			precMask					= functionCaseGroups[funcNdx].precMask;
2141e5c31af7Sopenharmony_ci
2142e5c31af7Sopenharmony_ci		// If this is a new function and not just a different version of the previously defined function, create a new group.
2143e5c31af7Sopenharmony_ci		if (funcNdx == 0 || parentGroup != functionCaseGroups[funcNdx-1].parentGroup || string(groupName) != functionCaseGroups[funcNdx-1].groupName)
2144e5c31af7Sopenharmony_ci		{
2145e5c31af7Sopenharmony_ci			tcu::TestCaseGroup* const funcGroup = new tcu::TestCaseGroup(m_testCtx, groupName, "");
2146e5c31af7Sopenharmony_ci			functionCaseGroups[funcNdx].parentGroup->addChild(funcGroup);
2147e5c31af7Sopenharmony_ci
2148e5c31af7Sopenharmony_ci			vertexSubGroup		= new tcu::TestCaseGroup(m_testCtx, "vertex", "");
2149e5c31af7Sopenharmony_ci			fragmentSubGroup	= new tcu::TestCaseGroup(m_testCtx, "fragment", "");
2150e5c31af7Sopenharmony_ci
2151e5c31af7Sopenharmony_ci			funcGroup->addChild(vertexSubGroup);
2152e5c31af7Sopenharmony_ci			funcGroup->addChild(fragmentSubGroup);
2153e5c31af7Sopenharmony_ci
2154e5c31af7Sopenharmony_ci			vertexSubGroupCalibrationStorage	= FunctionCase::InitialCalibrationStorage(new FunctionCase::InitialCalibration);
2155e5c31af7Sopenharmony_ci			fragmentSubGroupCalibrationStorage	= FunctionCase::InitialCalibrationStorage(new FunctionCase::InitialCalibration);
2156e5c31af7Sopenharmony_ci		}
2157e5c31af7Sopenharmony_ci
2158e5c31af7Sopenharmony_ci		DE_ASSERT(vertexSubGroup != DE_NULL);
2159e5c31af7Sopenharmony_ci		DE_ASSERT(fragmentSubGroup != DE_NULL);
2160e5c31af7Sopenharmony_ci
2161e5c31af7Sopenharmony_ci		// Find the type size range of parameters (e.g. from 2 to 4 in case of vectors).
2162e5c31af7Sopenharmony_ci		int genTypeFirstSize	= 1;
2163e5c31af7Sopenharmony_ci		int genTypeLastSize		= 1;
2164e5c31af7Sopenharmony_ci
2165e5c31af7Sopenharmony_ci		// Find the first return value or parameter with a gentype (if any) and set sizes accordingly.
2166e5c31af7Sopenharmony_ci		// \note Assumes only matching sizes gentypes are to be found, e.g. no "genType func (vec param)"
2167e5c31af7Sopenharmony_ci		for (int i = 0; i < FunctionCase::MAX_PARAMS + 1 && genTypeLastSize == 1; i++)
2168e5c31af7Sopenharmony_ci		{
2169e5c31af7Sopenharmony_ci			switch (funcTypes[i])
2170e5c31af7Sopenharmony_ci			{
2171e5c31af7Sopenharmony_ci				case VALUE_FLOAT_VEC:
2172e5c31af7Sopenharmony_ci				case VALUE_BOOL_VEC:
2173e5c31af7Sopenharmony_ci				case VALUE_INT_VEC:			// \note Fall-through.
2174e5c31af7Sopenharmony_ci					genTypeFirstSize = 2;
2175e5c31af7Sopenharmony_ci					genTypeLastSize = 4;
2176e5c31af7Sopenharmony_ci					break;
2177e5c31af7Sopenharmony_ci				case VALUE_FLOAT_VEC34:
2178e5c31af7Sopenharmony_ci					genTypeFirstSize = 3;
2179e5c31af7Sopenharmony_ci					genTypeLastSize = 4;
2180e5c31af7Sopenharmony_ci					break;
2181e5c31af7Sopenharmony_ci				case VALUE_FLOAT_GENTYPE:
2182e5c31af7Sopenharmony_ci				case VALUE_BOOL_GENTYPE:
2183e5c31af7Sopenharmony_ci				case VALUE_INT_GENTYPE:		// \note Fall-through.
2184e5c31af7Sopenharmony_ci					genTypeFirstSize = 1;
2185e5c31af7Sopenharmony_ci					genTypeLastSize = 4;
2186e5c31af7Sopenharmony_ci					break;
2187e5c31af7Sopenharmony_ci				case VALUE_MATRIX:
2188e5c31af7Sopenharmony_ci					genTypeFirstSize = 2;
2189e5c31af7Sopenharmony_ci					genTypeLastSize = 4;
2190e5c31af7Sopenharmony_ci					break;
2191e5c31af7Sopenharmony_ci				// If none of the above, keep looping.
2192e5c31af7Sopenharmony_ci				default:
2193e5c31af7Sopenharmony_ci					break;
2194e5c31af7Sopenharmony_ci			}
2195e5c31af7Sopenharmony_ci		}
2196e5c31af7Sopenharmony_ci
2197e5c31af7Sopenharmony_ci		// Create a case for each possible size of the gentype.
2198e5c31af7Sopenharmony_ci		for (int curSize = genTypeFirstSize; curSize <= genTypeLastSize; curSize++)
2199e5c31af7Sopenharmony_ci		{
2200e5c31af7Sopenharmony_ci			// Determine specific types for return value and the parameters, according to curSize. Non-gentypes not affected by curSize.
2201e5c31af7Sopenharmony_ci			DataType types[FunctionCase::MAX_PARAMS + 1];
2202e5c31af7Sopenharmony_ci			for (int i = 0; i < FunctionCase::MAX_PARAMS + 1; i++)
2203e5c31af7Sopenharmony_ci			{
2204e5c31af7Sopenharmony_ci				if (funcTypes[i] == VALUE_NONE)
2205e5c31af7Sopenharmony_ci					types[i] = TYPE_INVALID;
2206e5c31af7Sopenharmony_ci				else
2207e5c31af7Sopenharmony_ci				{
2208e5c31af7Sopenharmony_ci					int isFloat	= funcTypes[i] & VALUE_ANY_FLOAT;
2209e5c31af7Sopenharmony_ci					int isBool	= funcTypes[i] & VALUE_ANY_BOOL;
2210e5c31af7Sopenharmony_ci					int isInt	= funcTypes[i] & VALUE_ANY_INT;
2211e5c31af7Sopenharmony_ci					int isMat	= funcTypes[i] == VALUE_MATRIX;
2212e5c31af7Sopenharmony_ci					int inSize	= (funcTypes[i] & VALUE_ANY_GENTYPE)	? curSize
2213e5c31af7Sopenharmony_ci								: funcTypes[i] == VALUE_VEC3			? 3
2214e5c31af7Sopenharmony_ci								: funcTypes[i] == VALUE_VEC4			? 4
2215e5c31af7Sopenharmony_ci								: 1;
2216e5c31af7Sopenharmony_ci					int			typeArrayNdx = isMat ? inSize - 2 : inSize - 1; // \note No matrices of size 1.
2217e5c31af7Sopenharmony_ci
2218e5c31af7Sopenharmony_ci					types[i]	= isFloat	? floatTypes[typeArrayNdx]
2219e5c31af7Sopenharmony_ci								: isBool	? boolTypes[typeArrayNdx]
2220e5c31af7Sopenharmony_ci								: isInt		? intTypes[typeArrayNdx]
2221e5c31af7Sopenharmony_ci								: isMat		? matrixTypes[typeArrayNdx]
2222e5c31af7Sopenharmony_ci								: TYPE_LAST;
2223e5c31af7Sopenharmony_ci				}
2224e5c31af7Sopenharmony_ci
2225e5c31af7Sopenharmony_ci				DE_ASSERT(types[i] != TYPE_LAST);
2226e5c31af7Sopenharmony_ci			}
2227e5c31af7Sopenharmony_ci
2228e5c31af7Sopenharmony_ci			// Array for just the parameter types.
2229e5c31af7Sopenharmony_ci			DataType paramTypes[FunctionCase::MAX_PARAMS];
2230e5c31af7Sopenharmony_ci			for (int i = 0; i < FunctionCase::MAX_PARAMS; i++)
2231e5c31af7Sopenharmony_ci				paramTypes[i] = types[i+1];
2232e5c31af7Sopenharmony_ci
2233e5c31af7Sopenharmony_ci			for (int prec = (int)PRECISION_LOWP; prec < (int)PRECISION_LAST; prec++)
2234e5c31af7Sopenharmony_ci			{
2235e5c31af7Sopenharmony_ci				if ((precMask & (1 << prec)) == 0)
2236e5c31af7Sopenharmony_ci					continue;
2237e5c31af7Sopenharmony_ci
2238e5c31af7Sopenharmony_ci				const string		precisionPrefix = booleanCase ? "" : (string(getPrecisionName((Precision)prec)) + "_");
2239e5c31af7Sopenharmony_ci				std::ostringstream	caseName;
2240e5c31af7Sopenharmony_ci
2241e5c31af7Sopenharmony_ci				caseName << precisionPrefix;
2242e5c31af7Sopenharmony_ci
2243e5c31af7Sopenharmony_ci				// Write the name of each distinct parameter data type into the test case name.
2244e5c31af7Sopenharmony_ci				for (int i = 1; i < FunctionCase::MAX_PARAMS + 1 && types[i] != TYPE_INVALID; i++)
2245e5c31af7Sopenharmony_ci				{
2246e5c31af7Sopenharmony_ci					if (i == 1 || types[i] != types[i-1])
2247e5c31af7Sopenharmony_ci					{
2248e5c31af7Sopenharmony_ci						if (i > 1)
2249e5c31af7Sopenharmony_ci							caseName << "_";
2250e5c31af7Sopenharmony_ci
2251e5c31af7Sopenharmony_ci						caseName << getDataTypeName(types[i]);
2252e5c31af7Sopenharmony_ci					}
2253e5c31af7Sopenharmony_ci				}
2254e5c31af7Sopenharmony_ci
2255e5c31af7Sopenharmony_ci				for (int fragI = 0; fragI <= 1; fragI++)
2256e5c31af7Sopenharmony_ci				{
2257e5c31af7Sopenharmony_ci					const bool					vert	= fragI == 0;
2258e5c31af7Sopenharmony_ci					tcu::TestCaseGroup* const	group	= vert ? vertexSubGroup : fragmentSubGroup;
2259e5c31af7Sopenharmony_ci					group->addChild	(new FunctionCase(m_context,
2260e5c31af7Sopenharmony_ci													  caseName.str().c_str(), "",
2261e5c31af7Sopenharmony_ci													  groupFunc,
2262e5c31af7Sopenharmony_ci													  types[0], paramTypes,
2263e5c31af7Sopenharmony_ci													  groupAttribute, modifyParamNdx, useNearlyConstantInputs,
2264e5c31af7Sopenharmony_ci													  (Precision)prec, vert,
2265e5c31af7Sopenharmony_ci													  vert ? vertexSubGroupCalibrationStorage : fragmentSubGroupCalibrationStorage));
2266e5c31af7Sopenharmony_ci				}
2267e5c31af7Sopenharmony_ci			}
2268e5c31af7Sopenharmony_ci		}
2269e5c31af7Sopenharmony_ci	}
2270e5c31af7Sopenharmony_ci}
2271e5c31af7Sopenharmony_ci
2272e5c31af7Sopenharmony_ci} // Performance
2273e5c31af7Sopenharmony_ci} // gles2
2274e5c31af7Sopenharmony_ci} // deqp
2275