1/*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Long running shader stress tests.
22 *//*--------------------------------------------------------------------*/
23
24#include "es3sLongRunningShaderTests.hpp"
25
26#include "gluShaderProgram.hpp"
27#include "gluShaderUtil.hpp"
28#include "gluDrawUtil.hpp"
29
30#include "tcuRenderTarget.hpp"
31#include "tcuVector.hpp"
32#include "tcuTestLog.hpp"
33
34#include "deRandom.hpp"
35#include "deStringUtil.hpp"
36#include "deString.h"
37
38#include "glwFunctions.hpp"
39#include "glwEnums.hpp"
40
41namespace deqp
42{
43namespace gles3
44{
45namespace Stress
46{
47
48using tcu::TestLog;
49using tcu::Vec2;
50using std::vector;
51
52namespace
53{
54
55enum LoopType
56{
57	LOOPTYPE_FOR = 0,
58	LOOPTYPE_WHILE,
59	LOOPTYPE_DO_WHILE,
60
61	LOOPTYPE_LAST
62};
63
64enum IterCountType
65{
66	ITERCOUNTTYPE_STATIC = 0,
67	ITERCOUNTTYPE_UNIFORM,
68	ITERCOUNTTYPE_DYNAMIC,
69
70	ITERCOUNTTYPE_LAST
71};
72
73class LongRunningShaderCase : public TestCase
74{
75public:
76	struct Params
77	{
78		const char*			name;
79		const char*			description;
80		glu::ShaderType		shaderType;
81		LoopType			loopType;
82		IterCountType		iterCountType;
83		int					numInvocations;
84		int					minLoopIterCount;
85		int					maxLoopIterCount;
86	};
87
88								LongRunningShaderCase		(Context& context, const Params* params);
89								~LongRunningShaderCase		(void);
90
91	void						init						(void);
92	void						deinit						(void);
93	IterateResult				iterate						(void);
94
95private:
96								LongRunningShaderCase		(const LongRunningShaderCase&);
97	LongRunningShaderCase&		operator=					(const LongRunningShaderCase&);
98
99	static glu::ProgramSources	genSources					(const Params& params);
100	static deUint32				getSeed						(const Params& params);
101
102	const Params* const			m_params;
103	const int					m_numCaseIters;
104
105	glu::ShaderProgram*			m_program;
106	int							m_caseIterNdx;
107};
108
109LongRunningShaderCase::LongRunningShaderCase (Context& context, const Params* params)
110	: TestCase			(context, params->name, params->description)
111	, m_params			(params)
112	, m_numCaseIters	(5)
113	, m_program			(DE_NULL)
114	, m_caseIterNdx		(0)
115{
116}
117
118LongRunningShaderCase::~LongRunningShaderCase (void)
119{
120	deinit();
121}
122
123glu::ProgramSources LongRunningShaderCase::genSources (const Params& params)
124{
125	const bool			isVertCase		= params.shaderType == glu::SHADERTYPE_VERTEX;
126	std::ostringstream	vert, frag;
127
128	vert << "#version 300 es\n"
129		 << "in highp vec2 a_position;\n";
130
131	frag << "#version 300 es\n";
132
133	if (params.iterCountType == ITERCOUNTTYPE_DYNAMIC)
134	{
135		vert << "in highp int a_iterCount;\n";
136		if (!isVertCase)
137		{
138			vert << "flat out highp int v_iterCount;\n";
139			frag << "flat in highp int v_iterCount;\n";
140		}
141	}
142	else if (params.iterCountType == ITERCOUNTTYPE_UNIFORM)
143		(isVertCase ? vert : frag) << "uniform highp int u_iterCount;\n";
144
145	if (isVertCase)
146	{
147		vert << "out mediump vec4 v_color;\n";
148		frag << "in mediump vec4 v_color;\n";
149	}
150
151	frag << "out mediump vec4 o_color;\n";
152
153	vert << "\nvoid main (void)\n{\n"
154		 << "	gl_Position = vec4(a_position, 0.0, 1.0);\n"
155		 << "	gl_PointSize = 1.0;\n";
156
157	if (!isVertCase && params.iterCountType == ITERCOUNTTYPE_DYNAMIC)
158		vert << "	v_iterCount = a_iterCount;\n";
159
160	frag << "\nvoid main (void)\n{\n";
161
162	{
163		const std::string	iterCount	= params.iterCountType == ITERCOUNTTYPE_DYNAMIC ? (isVertCase ? "a_iterCount" : "v_iterCount")	:
164										  params.iterCountType == ITERCOUNTTYPE_UNIFORM ? "u_iterCount"									:
165										  params.iterCountType == ITERCOUNTTYPE_STATIC	? de::toString(params.maxLoopIterCount)			: "<invalid>";
166		const char* const	body		= "color = cos(sin(color*1.25)*0.8);";
167		std::ostringstream&	op			= isVertCase ? vert : frag;
168
169		op << "	mediump vec4 color = " << (isVertCase ? "a_position.xyxy" : "gl_FragCoord") << ";\n";
170
171		if (params.loopType == LOOPTYPE_FOR)
172		{
173			op << "	for (highp int i = 0; i < " << iterCount << " || " << iterCount << " < 0; ++i)\n"
174			   << "		" << body << "\n";
175		}
176		else if (params.loopType == LOOPTYPE_WHILE)
177		{
178			op << "	highp int i = 0;\n"
179			   << "	while (i < " << iterCount << " || " << iterCount << " < 0) {\n"
180			   << "		i += 1;\n"
181			   << "		" << body << "\n"
182			   << "	}\n";
183		}
184		else
185		{
186			DE_ASSERT(params.loopType == LOOPTYPE_DO_WHILE);
187			op << "	highp int i = 0;\n"
188			   << "	do {\n"
189			   << "		i += 1;\n"
190			   << "		" << body << "\n"
191			   << "	} while (i <= " << iterCount << " || " << iterCount << " < 0);\n";
192		}
193	}
194
195	if (isVertCase)
196	{
197		vert << "	v_color = color;\n";
198		frag << "	o_color = v_color;\n";
199	}
200	else
201		frag << "	o_color = color;\n";
202
203	vert << "}\n";
204	frag << "}\n";
205
206	return glu::ProgramSources() << glu::VertexSource(vert.str()) << glu::FragmentSource(frag.str());
207}
208
209void LongRunningShaderCase::init (void)
210{
211	DE_ASSERT(!m_program);
212	m_program = new glu::ShaderProgram(m_context.getRenderContext(), genSources(*m_params));
213
214	m_testCtx.getLog() << *m_program;
215
216	if (!m_program->isOk())
217	{
218		deinit();
219		TCU_FAIL("Failed to compile shader program");
220	}
221
222	m_caseIterNdx = 0;
223
224	if (m_params->iterCountType != ITERCOUNTTYPE_STATIC)
225	{
226		m_testCtx.getLog() << TestLog::Message << "Loop iteration counts in range: [" << m_params->minLoopIterCount
227											   << ", " << m_params->maxLoopIterCount << "]"
228						   << TestLog::EndMessage;
229	}
230
231	m_testCtx.getLog() << TestLog::Message << "Number of vertices and fragments: " << m_params->numInvocations << TestLog::EndMessage;
232
233	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); // Test will pass or timeout, unless driver/device crashes.
234}
235
236void LongRunningShaderCase::deinit (void)
237{
238	delete m_program;
239	m_program = DE_NULL;
240}
241
242void genPositions (const tcu::RenderTarget& renderTarget, int numPoints, Vec2* positions)
243{
244	const int	width		= renderTarget.getWidth();
245	const int	height		= renderTarget.getHeight();
246
247	if (width*height < numPoints)
248		throw tcu::NotSupportedError("Too small viewport to fit all test points");
249
250	for (int pointNdx = 0; pointNdx < numPoints; pointNdx++)
251	{
252		const int		xi		= pointNdx % width;
253		const int		yi		= pointNdx / height;
254		const float		xf		= 2.0f * ((float(xi) + 0.5f) / float(width)) - 1.0f;
255		const float		yf		= 2.0f * ((float(yi) + 0.5f) / float(height)) - 1.0f;
256
257		positions[pointNdx] = Vec2(xf, yf);
258	}
259}
260
261deUint32 LongRunningShaderCase::getSeed (const Params& params)
262{
263	const deUint32	seed	= deStringHash(params.name)
264							^ deInt32Hash(params.shaderType)
265							^ deInt32Hash(params.loopType)
266							^ deInt32Hash(params.iterCountType)
267							^ deInt32Hash(params.minLoopIterCount)
268							^ deInt32Hash(params.maxLoopIterCount)
269							^ deInt32Hash(params.numInvocations);
270	return seed;
271}
272
273LongRunningShaderCase::IterateResult LongRunningShaderCase::iterate (void)
274{
275	const glw::Functions&			gl				= m_context.getRenderContext().getFunctions();
276	de::Random						rnd				(getSeed(*m_params));
277	vector<Vec2>					positions		(m_params->numInvocations);
278	vector<int>						iterCounts		(m_params->iterCountType == ITERCOUNTTYPE_DYNAMIC ? m_params->numInvocations : 1);
279	vector<glu::VertexArrayBinding>	vertexArrays;
280
281	vertexArrays.push_back(glu::va::Float("a_position", 2, (int)positions.size(), 0, positions[0].getPtr()));
282	if (m_params->iterCountType == ITERCOUNTTYPE_DYNAMIC)
283		vertexArrays.push_back(glu::va::Int32("a_iterCount", 1, (int)iterCounts.size(), 0, &iterCounts[0]));
284
285	genPositions(m_context.getRenderTarget(), (int)positions.size(), &positions[0]);
286
287	for (vector<int>::iterator i = iterCounts.begin(); i != iterCounts.end(); ++i)
288		*i = rnd.getInt(m_params->minLoopIterCount, m_params->maxLoopIterCount);
289
290	gl.useProgram(m_program->getProgram());
291
292	if (m_params->iterCountType == ITERCOUNTTYPE_UNIFORM)
293		gl.uniform1i(gl.getUniformLocation(m_program->getProgram(), "u_iterCount"), iterCounts[0]);
294
295	glu::draw(m_context.getRenderContext(), m_program->getProgram(),
296			  (int)vertexArrays.size(), &vertexArrays[0],
297			  glu::pr::Points(m_params->numInvocations));
298
299	m_caseIterNdx += 1;
300	return (m_caseIterNdx < m_numCaseIters) ? CONTINUE : STOP;
301}
302
303} // anonymous
304
305LongRunningShaderTests::LongRunningShaderTests (Context& context)
306	: TestCaseGroup(context, "long_running_shaders",	"Long-running shader stress tests")
307{
308}
309
310LongRunningShaderTests::~LongRunningShaderTests (void)
311{
312}
313
314void LongRunningShaderTests::init (void)
315{
316	const int	numInvocations	= 4096;
317	const int	shortLoopMin	= 5;
318	const int	shortLoopMax	= 10;
319	const int	mediumLoopMin	= 10000;
320	const int	mediumLoopMax	= 50000;
321	const int	longLoopMin		= 100000;
322	const int	longLoopMax		= 500000;
323
324	static const LongRunningShaderCase::Params s_cases[] =
325	{
326		{ "short_for_vertex",					"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_FOR,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	shortLoopMin,	shortLoopMax	},
327		{ "short_for_fragment",					"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_FOR,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	shortLoopMin,	shortLoopMax	},
328		{ "short_while_vertex",					"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_WHILE,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	shortLoopMin,	shortLoopMax	},
329		{ "short_while_fragment",				"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_WHILE,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	shortLoopMin,	shortLoopMax	},
330		{ "short_do_while_vertex",				"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_DO_WHILE,	ITERCOUNTTYPE_DYNAMIC,	numInvocations,	shortLoopMin,	shortLoopMax	},
331		{ "short_do_while_fragment",			"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_DO_WHILE,	ITERCOUNTTYPE_DYNAMIC,	numInvocations,	shortLoopMin,	shortLoopMax	},
332
333		{ "medium_static_for_vertex",			"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_FOR,		ITERCOUNTTYPE_STATIC,	numInvocations,	mediumLoopMin,	mediumLoopMax	},
334		{ "medium_static_while_fragment",		"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_WHILE,		ITERCOUNTTYPE_STATIC,	numInvocations,	mediumLoopMin,	mediumLoopMax	},
335		{ "medium_uniform_do_while_vertex",		"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_DO_WHILE,	ITERCOUNTTYPE_UNIFORM,	numInvocations,	mediumLoopMin,	mediumLoopMax	},
336		{ "medium_uniform_for_fragment",		"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_FOR,		ITERCOUNTTYPE_UNIFORM,	numInvocations,	mediumLoopMin,	mediumLoopMax	},
337
338		{ "medium_dynamic_for_vertex",			"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_FOR,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	mediumLoopMin,	mediumLoopMax	},
339		{ "medium_dynamic_for_fragment",		"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_FOR,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	mediumLoopMin,	mediumLoopMax	},
340		{ "medium_dynamic_while_vertex",		"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_WHILE,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	mediumLoopMin,	mediumLoopMax	},
341		{ "medium_dynamic_while_fragment",		"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_WHILE,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	mediumLoopMin,	mediumLoopMax	},
342		{ "medium_dynamic_do_while_vertex",		"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_DO_WHILE,	ITERCOUNTTYPE_DYNAMIC,	numInvocations,	mediumLoopMin,	mediumLoopMax	},
343		{ "medium_dynamic_do_while_fragment",	"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_DO_WHILE,	ITERCOUNTTYPE_DYNAMIC,	numInvocations,	mediumLoopMin,	mediumLoopMax	},
344
345		{ "long_static_while_vertex",			"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_WHILE,		ITERCOUNTTYPE_STATIC,	numInvocations,	longLoopMin,	longLoopMax		},
346		{ "long_static_do_while_fragment",		"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_DO_WHILE,	ITERCOUNTTYPE_STATIC,	numInvocations,	longLoopMin,	longLoopMax		},
347		{ "long_uniform_for_vertex",			"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_FOR,		ITERCOUNTTYPE_UNIFORM,	numInvocations,	longLoopMin,	longLoopMax		},
348		{ "long_uniform_do_while_fragment",		"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_DO_WHILE,	ITERCOUNTTYPE_UNIFORM,	numInvocations,	longLoopMin,	longLoopMax		},
349
350		{ "long_dynamic_for_vertex",			"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_FOR,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	longLoopMin,	longLoopMax		},
351		{ "long_dynamic_for_fragment",			"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_FOR,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	longLoopMin,	longLoopMax		},
352		{ "long_dynamic_while_vertex",			"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_WHILE,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	longLoopMin,	longLoopMax		},
353		{ "long_dynamic_while_fragment",		"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_WHILE,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	longLoopMin,	longLoopMax		},
354		{ "long_dynamic_do_while_vertex",		"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_DO_WHILE,	ITERCOUNTTYPE_DYNAMIC,	numInvocations,	longLoopMin,	longLoopMax		},
355		{ "long_dynamic_do_while_fragment",		"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_DO_WHILE,	ITERCOUNTTYPE_DYNAMIC,	numInvocations,	longLoopMin,	longLoopMax		},
356
357		{ "infinite_for_vertex",				"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_FOR,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	-1,				-1				},
358		{ "infinite_for_fragment",				"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_FOR,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	-1,				-1				},
359		{ "infinite_while_vertex",				"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_WHILE,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	-1,				-1				},
360		{ "infinite_while_fragment",			"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_WHILE,		ITERCOUNTTYPE_DYNAMIC,	numInvocations,	-1,				-1				},
361		{ "infinite_do_while_vertex",			"",	glu::SHADERTYPE_VERTEX,		LOOPTYPE_DO_WHILE,	ITERCOUNTTYPE_DYNAMIC,	numInvocations,	-1,				-1				},
362		{ "infinite_do_while_fragment",			"",	glu::SHADERTYPE_FRAGMENT,	LOOPTYPE_DO_WHILE,	ITERCOUNTTYPE_DYNAMIC,	numInvocations,	-1,				-1				},
363	};
364
365	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_cases); ndx++)
366		addChild(new LongRunningShaderCase(m_context, &s_cases[ndx]));
367}
368
369} // Stress
370} // gles3
371} // deqp
372