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
41 namespace deqp
42 {
43 namespace gles3
44 {
45 namespace Stress
46 {
47
48 using std::vector;
49 using tcu::TestLog;
50 using tcu::Vec2;
51
52 namespace
53 {
54
55 enum LoopType
56 {
57 LOOPTYPE_FOR = 0,
58 LOOPTYPE_WHILE,
59 LOOPTYPE_DO_WHILE,
60
61 LOOPTYPE_LAST
62 };
63
64 enum IterCountType
65 {
66 ITERCOUNTTYPE_STATIC = 0,
67 ITERCOUNTTYPE_UNIFORM,
68 ITERCOUNTTYPE_DYNAMIC,
69
70 ITERCOUNTTYPE_LAST
71 };
72
73 class LongRunningShaderCase : public TestCase
74 {
75 public:
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
95 private:
96 LongRunningShaderCase(const LongRunningShaderCase &);
97 LongRunningShaderCase &operator=(const LongRunningShaderCase &);
98
99 static glu::ProgramSources genSources(const Params ¶ms);
100 static uint32_t getSeed(const Params ¶ms);
101
102 const Params *const m_params;
103 const int m_numCaseIters;
104
105 glu::ShaderProgram *m_program;
106 int m_caseIterNdx;
107 };
108
LongRunningShaderCase(Context & context,const Params * params)109 LongRunningShaderCase::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
~LongRunningShaderCase(void)118 LongRunningShaderCase::~LongRunningShaderCase(void)
119 {
120 deinit();
121 }
122
genSources(const Params & params)123 glu::ProgramSources LongRunningShaderCase::genSources(const Params ¶ms)
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 =
164 params.iterCountType == ITERCOUNTTYPE_DYNAMIC ? (isVertCase ? "a_iterCount" : "v_iterCount") :
165 params.iterCountType == ITERCOUNTTYPE_UNIFORM ? "u_iterCount" :
166 params.iterCountType == ITERCOUNTTYPE_STATIC ? de::toString(params.maxLoopIterCount) :
167 "<invalid>";
168 const char *const body = "color = cos(sin(color*1.25)*0.8);";
169 std::ostringstream &op = isVertCase ? vert : frag;
170
171 op << " mediump vec4 color = " << (isVertCase ? "a_position.xyxy" : "gl_FragCoord") << ";\n";
172
173 if (params.loopType == LOOPTYPE_FOR)
174 {
175 op << " for (highp int i = 0; i < " << iterCount << " || " << iterCount << " < 0; ++i)\n"
176 << " " << body << "\n";
177 }
178 else if (params.loopType == LOOPTYPE_WHILE)
179 {
180 op << " highp int i = 0;\n"
181 << " while (i < " << iterCount << " || " << iterCount << " < 0) {\n"
182 << " i += 1;\n"
183 << " " << body << "\n"
184 << " }\n";
185 }
186 else
187 {
188 DE_ASSERT(params.loopType == LOOPTYPE_DO_WHILE);
189 op << " highp int i = 0;\n"
190 << " do {\n"
191 << " i += 1;\n"
192 << " " << body << "\n"
193 << " } while (i <= " << iterCount << " || " << iterCount << " < 0);\n";
194 }
195 }
196
197 if (isVertCase)
198 {
199 vert << " v_color = color;\n";
200 frag << " o_color = v_color;\n";
201 }
202 else
203 frag << " o_color = color;\n";
204
205 vert << "}\n";
206 frag << "}\n";
207
208 return glu::ProgramSources() << glu::VertexSource(vert.str()) << glu::FragmentSource(frag.str());
209 }
210
init(void)211 void LongRunningShaderCase::init(void)
212 {
213 DE_ASSERT(!m_program);
214 m_program = new glu::ShaderProgram(m_context.getRenderContext(), genSources(*m_params));
215
216 m_testCtx.getLog() << *m_program;
217
218 if (!m_program->isOk())
219 {
220 deinit();
221 TCU_FAIL("Failed to compile shader program");
222 }
223
224 m_caseIterNdx = 0;
225
226 if (m_params->iterCountType != ITERCOUNTTYPE_STATIC)
227 {
228 m_testCtx.getLog() << TestLog::Message << "Loop iteration counts in range: [" << m_params->minLoopIterCount
229 << ", " << m_params->maxLoopIterCount << "]" << TestLog::EndMessage;
230 }
231
232 m_testCtx.getLog() << TestLog::Message << "Number of vertices and fragments: " << m_params->numInvocations
233 << TestLog::EndMessage;
234
235 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); // Test will pass or timeout, unless driver/device crashes.
236 }
237
deinit(void)238 void LongRunningShaderCase::deinit(void)
239 {
240 delete m_program;
241 m_program = DE_NULL;
242 }
243
genPositions(const tcu::RenderTarget & renderTarget,int numPoints,Vec2 * positions)244 void genPositions(const tcu::RenderTarget &renderTarget, int numPoints, Vec2 *positions)
245 {
246 const int width = renderTarget.getWidth();
247 const int height = renderTarget.getHeight();
248
249 if (width * height < numPoints)
250 throw tcu::NotSupportedError("Too small viewport to fit all test points");
251
252 for (int pointNdx = 0; pointNdx < numPoints; pointNdx++)
253 {
254 const int xi = pointNdx % width;
255 const int yi = pointNdx / height;
256 const float xf = 2.0f * ((float(xi) + 0.5f) / float(width)) - 1.0f;
257 const float yf = 2.0f * ((float(yi) + 0.5f) / float(height)) - 1.0f;
258
259 positions[pointNdx] = Vec2(xf, yf);
260 }
261 }
262
getSeed(const Params & params)263 uint32_t LongRunningShaderCase::getSeed(const Params ¶ms)
264 {
265 const uint32_t seed = deStringHash(params.name) ^ deInt32Hash(params.shaderType) ^ deInt32Hash(params.loopType) ^
266 deInt32Hash(params.iterCountType) ^ deInt32Hash(params.minLoopIterCount) ^
267 deInt32Hash(params.maxLoopIterCount) ^ deInt32Hash(params.numInvocations);
268 return seed;
269 }
270
iterate(void)271 LongRunningShaderCase::IterateResult LongRunningShaderCase::iterate(void)
272 {
273 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
274 de::Random rnd(getSeed(*m_params));
275 vector<Vec2> positions(m_params->numInvocations);
276 vector<int> iterCounts(m_params->iterCountType == ITERCOUNTTYPE_DYNAMIC ? m_params->numInvocations : 1);
277 vector<glu::VertexArrayBinding> vertexArrays;
278
279 vertexArrays.push_back(glu::va::Float("a_position", 2, (int)positions.size(), 0, positions[0].getPtr()));
280 if (m_params->iterCountType == ITERCOUNTTYPE_DYNAMIC)
281 vertexArrays.push_back(glu::va::Int32("a_iterCount", 1, (int)iterCounts.size(), 0, &iterCounts[0]));
282
283 genPositions(m_context.getRenderTarget(), (int)positions.size(), &positions[0]);
284
285 for (vector<int>::iterator i = iterCounts.begin(); i != iterCounts.end(); ++i)
286 *i = rnd.getInt(m_params->minLoopIterCount, m_params->maxLoopIterCount);
287
288 gl.useProgram(m_program->getProgram());
289
290 if (m_params->iterCountType == ITERCOUNTTYPE_UNIFORM)
291 gl.uniform1i(gl.getUniformLocation(m_program->getProgram(), "u_iterCount"), iterCounts[0]);
292
293 glu::draw(m_context.getRenderContext(), m_program->getProgram(), (int)vertexArrays.size(), &vertexArrays[0],
294 glu::pr::Points(m_params->numInvocations));
295
296 m_caseIterNdx += 1;
297 return (m_caseIterNdx < m_numCaseIters) ? CONTINUE : STOP;
298 }
299
300 } // namespace
301
LongRunningShaderTests(Context & context)302 LongRunningShaderTests::LongRunningShaderTests(Context &context)
303 : TestCaseGroup(context, "long_running_shaders", "Long-running shader stress tests")
304 {
305 }
306
~LongRunningShaderTests(void)307 LongRunningShaderTests::~LongRunningShaderTests(void)
308 {
309 }
310
init(void)311 void LongRunningShaderTests::init(void)
312 {
313 const int numInvocations = 4096;
314 const int shortLoopMin = 5;
315 const int shortLoopMax = 10;
316 const int mediumLoopMin = 10000;
317 const int mediumLoopMax = 50000;
318 const int longLoopMin = 100000;
319 const int longLoopMax = 500000;
320
321 static const LongRunningShaderCase::Params s_cases[] = {
322 {"short_for_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations,
323 shortLoopMin, shortLoopMax},
324 {"short_for_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations,
325 shortLoopMin, shortLoopMax},
326 {"short_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations,
327 shortLoopMin, shortLoopMax},
328 {"short_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations,
329 shortLoopMin, shortLoopMax},
330 {"short_do_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations,
331 shortLoopMin, shortLoopMax},
332 {"short_do_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC,
333 numInvocations, shortLoopMin, shortLoopMax},
334
335 {"medium_static_for_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_FOR, ITERCOUNTTYPE_STATIC, numInvocations,
336 mediumLoopMin, mediumLoopMax},
337 {"medium_static_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_WHILE, ITERCOUNTTYPE_STATIC,
338 numInvocations, mediumLoopMin, mediumLoopMax},
339 {"medium_uniform_do_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_UNIFORM,
340 numInvocations, mediumLoopMin, mediumLoopMax},
341 {"medium_uniform_for_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_FOR, ITERCOUNTTYPE_UNIFORM,
342 numInvocations, mediumLoopMin, mediumLoopMax},
343
344 {"medium_dynamic_for_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations,
345 mediumLoopMin, mediumLoopMax},
346 {"medium_dynamic_for_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC,
347 numInvocations, mediumLoopMin, mediumLoopMax},
348 {"medium_dynamic_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC,
349 numInvocations, mediumLoopMin, mediumLoopMax},
350 {"medium_dynamic_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC,
351 numInvocations, mediumLoopMin, mediumLoopMax},
352 {"medium_dynamic_do_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC,
353 numInvocations, mediumLoopMin, mediumLoopMax},
354 {"medium_dynamic_do_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC,
355 numInvocations, mediumLoopMin, mediumLoopMax},
356
357 {"long_static_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_WHILE, ITERCOUNTTYPE_STATIC, numInvocations,
358 longLoopMin, longLoopMax},
359 {"long_static_do_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_STATIC,
360 numInvocations, longLoopMin, longLoopMax},
361 {"long_uniform_for_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_FOR, ITERCOUNTTYPE_UNIFORM, numInvocations,
362 longLoopMin, longLoopMax},
363 {"long_uniform_do_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_UNIFORM,
364 numInvocations, longLoopMin, longLoopMax},
365
366 {"long_dynamic_for_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations,
367 longLoopMin, longLoopMax},
368 {"long_dynamic_for_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations,
369 longLoopMin, longLoopMax},
370 {"long_dynamic_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations,
371 longLoopMin, longLoopMax},
372 {"long_dynamic_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC,
373 numInvocations, longLoopMin, longLoopMax},
374 {"long_dynamic_do_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC,
375 numInvocations, longLoopMin, longLoopMax},
376 {"long_dynamic_do_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC,
377 numInvocations, longLoopMin, longLoopMax},
378
379 {"infinite_for_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations, -1,
380 -1},
381 {"infinite_for_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_FOR, ITERCOUNTTYPE_DYNAMIC, numInvocations, -1,
382 -1},
383 {"infinite_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations, -1,
384 -1},
385 {"infinite_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_WHILE, ITERCOUNTTYPE_DYNAMIC, numInvocations,
386 -1, -1},
387 {"infinite_do_while_vertex", "", glu::SHADERTYPE_VERTEX, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC,
388 numInvocations, -1, -1},
389 {"infinite_do_while_fragment", "", glu::SHADERTYPE_FRAGMENT, LOOPTYPE_DO_WHILE, ITERCOUNTTYPE_DYNAMIC,
390 numInvocations, -1, -1},
391 };
392
393 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_cases); ndx++)
394 addChild(new LongRunningShaderCase(m_context, &s_cases[ndx]));
395 }
396
397 } // namespace Stress
398 } // namespace gles3
399 } // namespace deqp
400