1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 2.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 Invariance tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es2fShaderInvarianceTests.hpp"
25 #include "deStringUtil.hpp"
26 #include "deRandom.hpp"
27 #include "gluContextInfo.hpp"
28 #include "gluRenderContext.hpp"
29 #include "gluShaderProgram.hpp"
30 #include "gluPixelTransfer.hpp"
31 #include "glwFunctions.hpp"
32 #include "glwEnums.hpp"
33 #include "tcuRenderTarget.hpp"
34 #include "tcuTestLog.hpp"
35 #include "tcuSurface.hpp"
36 #include "tcuTextureUtil.hpp"
37 #include "tcuStringTemplate.hpp"
38
39 namespace deqp
40 {
41 namespace gles2
42 {
43 namespace Functional
44 {
45 namespace
46 {
47
48 class FormatArgumentList;
49
genRandomVector(de::Random & rnd)50 static tcu::Vec4 genRandomVector(de::Random &rnd)
51 {
52 tcu::Vec4 retVal;
53
54 retVal.x() = rnd.getFloat(-1.0f, 1.0f);
55 retVal.y() = rnd.getFloat(-1.0f, 1.0f);
56 retVal.z() = rnd.getFloat(-1.0f, 1.0f);
57 retVal.w() = rnd.getFloat(0.2f, 1.0f);
58
59 return retVal;
60 }
61
62 class FormatArgument
63 {
64 public:
65 FormatArgument(const char *name, const std::string &value);
66
67 private:
68 friend class FormatArgumentList;
69
70 const char *const m_name;
71 const std::string m_value;
72 };
73
FormatArgument(const char * name,const std::string & value)74 FormatArgument::FormatArgument(const char *name, const std::string &value) : m_name(name), m_value(value)
75 {
76 }
77
78 class FormatArgumentList
79 {
80 public:
81 FormatArgumentList(void);
82
83 FormatArgumentList &operator<<(const FormatArgument &);
84 const std::map<std::string, std::string> &getArguments(void) const;
85
86 private:
87 std::map<std::string, std::string> m_formatArguments;
88 };
89
FormatArgumentList(void)90 FormatArgumentList::FormatArgumentList(void)
91 {
92 }
93
operator <<(const FormatArgument & arg)94 FormatArgumentList &FormatArgumentList::operator<<(const FormatArgument &arg)
95 {
96 m_formatArguments[arg.m_name] = arg.m_value;
97 return *this;
98 }
99
getArguments(void) const100 const std::map<std::string, std::string> &FormatArgumentList::getArguments(void) const
101 {
102 return m_formatArguments;
103 }
104
formatGLSL(const char * templateString,const FormatArgumentList & args)105 static std::string formatGLSL(const char *templateString, const FormatArgumentList &args)
106 {
107 const std::map<std::string, std::string> ¶ms = args.getArguments();
108
109 return tcu::StringTemplate(std::string(templateString)).specialize(params);
110 }
111
112 /*--------------------------------------------------------------------*//*!
113 * \brief Vertex shader invariance test
114 *
115 * Test vertex shader invariance by drawing a test pattern two times, each
116 * time with a different shader. Shaders have set identical values to
117 * invariant gl_Position using identical expressions. No fragments from the
118 * first pass using should remain visible.
119 *//*--------------------------------------------------------------------*/
120 class InvarianceTest : public TestCase
121 {
122 public:
123 struct ShaderPair
124 {
125 std::string vertexShaderSource0;
126 std::string fragmentShaderSource0;
127 std::string vertexShaderSource1;
128 std::string fragmentShaderSource1;
129 };
130
131 InvarianceTest(Context &ctx, const char *name, const char *desc);
132 ~InvarianceTest(void);
133
134 void init(void);
135 void deinit(void);
136 IterateResult iterate(void);
137
138 private:
139 virtual ShaderPair genShaders(void) const = DE_NULL;
140 bool checkImage(const tcu::Surface &) const;
141
142 glu::ShaderProgram *m_shader0;
143 glu::ShaderProgram *m_shader1;
144 glw::GLuint m_arrayBuf;
145 int m_verticesInPattern;
146
147 const int m_renderSize;
148 };
149
InvarianceTest(Context & ctx,const char * name,const char * desc)150 InvarianceTest::InvarianceTest(Context &ctx, const char *name, const char *desc)
151 : TestCase(ctx, name, desc)
152 , m_shader0(DE_NULL)
153 , m_shader1(DE_NULL)
154 , m_arrayBuf(0)
155 , m_verticesInPattern(0)
156 , m_renderSize(256)
157 {
158 }
159
~InvarianceTest(void)160 InvarianceTest::~InvarianceTest(void)
161 {
162 deinit();
163 }
164
init(void)165 void InvarianceTest::init(void)
166 {
167 // Invariance tests require drawing to the screen and reading back results.
168 // Tests results are not reliable if the resolution is too small
169 {
170 if (m_context.getRenderTarget().getWidth() < m_renderSize ||
171 m_context.getRenderTarget().getHeight() < m_renderSize)
172 throw tcu::NotSupportedError(std::string("Render target size must be at least ") +
173 de::toString(m_renderSize) + "x" + de::toString(m_renderSize));
174 }
175
176 // Gen shaders
177 {
178 ShaderPair vertexShaders = genShaders();
179
180 m_shader0 =
181 new glu::ShaderProgram(m_context.getRenderContext(),
182 glu::ProgramSources() << glu::VertexSource(vertexShaders.vertexShaderSource0)
183 << glu::FragmentSource(vertexShaders.fragmentShaderSource0));
184 if (!m_shader0->isOk())
185 {
186 m_testCtx.getLog() << *m_shader0;
187 throw tcu::TestError("Test shader compile failed.");
188 }
189
190 m_shader1 =
191 new glu::ShaderProgram(m_context.getRenderContext(),
192 glu::ProgramSources() << glu::VertexSource(vertexShaders.vertexShaderSource1)
193 << glu::FragmentSource(vertexShaders.fragmentShaderSource1));
194 if (!m_shader1->isOk())
195 {
196 m_testCtx.getLog() << *m_shader1;
197 throw tcu::TestError("Test shader compile failed.");
198 }
199
200 // log
201 m_testCtx.getLog() << tcu::TestLog::Message << "Shader 1:" << tcu::TestLog::EndMessage << *m_shader0
202 << tcu::TestLog::Message << "Shader 2:" << tcu::TestLog::EndMessage << *m_shader1;
203 }
204
205 // Gen test pattern
206 {
207 const int numTriangles = 72;
208 de::Random rnd(123);
209 std::vector<tcu::Vec4> triangles(numTriangles * 3 * 2);
210 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
211
212 // Narrow triangle pattern
213 for (int triNdx = 0; triNdx < numTriangles; ++triNdx)
214 {
215 const tcu::Vec4 vertex1 = genRandomVector(rnd);
216 const tcu::Vec4 vertex2 = genRandomVector(rnd);
217 const tcu::Vec4 vertex3 = vertex2 + genRandomVector(rnd) * 0.01f; // generate narrow triangles
218
219 triangles[triNdx * 3 + 0] = vertex1;
220 triangles[triNdx * 3 + 1] = vertex2;
221 triangles[triNdx * 3 + 2] = vertex3;
222 }
223
224 // Normal triangle pattern
225 for (int triNdx = 0; triNdx < numTriangles; ++triNdx)
226 {
227 triangles[(numTriangles + triNdx) * 3 + 0] = genRandomVector(rnd);
228 triangles[(numTriangles + triNdx) * 3 + 1] = genRandomVector(rnd);
229 triangles[(numTriangles + triNdx) * 3 + 2] = genRandomVector(rnd);
230 }
231
232 // upload
233 gl.genBuffers(1, &m_arrayBuf);
234 gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
235 gl.bufferData(GL_ARRAY_BUFFER, (int)(triangles.size() * sizeof(tcu::Vec4)), &triangles[0], GL_STATIC_DRAW);
236 GLU_EXPECT_NO_ERROR(gl.getError(), "buffer gen");
237
238 m_verticesInPattern = numTriangles * 3;
239 }
240 }
241
deinit(void)242 void InvarianceTest::deinit(void)
243 {
244 delete m_shader0;
245 delete m_shader1;
246
247 m_shader0 = DE_NULL;
248 m_shader1 = DE_NULL;
249
250 if (m_arrayBuf)
251 {
252 m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_arrayBuf);
253 m_arrayBuf = 0;
254 }
255 }
256
iterate(void)257 InvarianceTest::IterateResult InvarianceTest::iterate(void)
258 {
259 const glw::Functions &gl = m_context.getRenderContext().getFunctions();
260 const bool depthBufferExists = m_context.getRenderTarget().getDepthBits() != 0;
261 tcu::Surface resultSurface(m_renderSize, m_renderSize);
262 bool error = false;
263
264 // Prepare draw
265 gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
266 gl.clear(GL_COLOR_BUFFER_BIT);
267 gl.viewport(0, 0, m_renderSize, m_renderSize);
268 gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
269 GLU_EXPECT_NO_ERROR(gl.getError(), "setup draw");
270
271 m_testCtx.getLog() << tcu::TestLog::Message << "Testing position invariance." << tcu::TestLog::EndMessage;
272
273 // Draw position check passes
274 for (int passNdx = 0; passNdx < 2; ++passNdx)
275 {
276 const glu::ShaderProgram &shader = (passNdx == 0) ? (*m_shader0) : (*m_shader1);
277 const glw::GLint positionLoc = gl.getAttribLocation(shader.getProgram(), "a_input");
278 const glw::GLint colorLoc = gl.getUniformLocation(shader.getProgram(), "u_color");
279 const tcu::Vec4 red = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
280 const tcu::Vec4 green = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
281 const tcu::Vec4 color = (passNdx == 0) ? (red) : (green);
282 const char *const colorStr = (passNdx == 0) ? ("red - purple") : ("green");
283
284 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing position test pattern using shader " << (passNdx + 1)
285 << ". Primitive color: " << colorStr << "." << tcu::TestLog::EndMessage;
286
287 gl.useProgram(shader.getProgram());
288 gl.uniform4fv(colorLoc, 1, color.getPtr());
289 gl.enableVertexAttribArray(positionLoc);
290 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, sizeof(tcu::Vec4), DE_NULL);
291 gl.drawArrays(GL_TRIANGLES, 0, m_verticesInPattern);
292 gl.disableVertexAttribArray(positionLoc);
293 GLU_EXPECT_NO_ERROR(gl.getError(), "draw pass");
294 }
295
296 // Read result
297 glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess());
298
299 // Check there are no red pixels
300 m_testCtx.getLog() << tcu::TestLog::Message
301 << "Verifying output. Expecting only green or background colored pixels."
302 << tcu::TestLog::EndMessage;
303 error |= !checkImage(resultSurface);
304
305 if (!depthBufferExists)
306 {
307 m_testCtx.getLog() << tcu::TestLog::Message << "Depth buffer not available, skipping z-test."
308 << tcu::TestLog::EndMessage;
309 }
310 else
311 {
312 // Test with Z-test
313 gl.clearDepthf(1.0f);
314 gl.clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
315 gl.enable(GL_DEPTH_TEST);
316
317 m_testCtx.getLog() << tcu::TestLog::Message
318 << "Testing position invariance with z-test. Enabling GL_DEPTH_TEST."
319 << tcu::TestLog::EndMessage;
320
321 // Draw position check passes
322 for (int passNdx = 0; passNdx < 2; ++passNdx)
323 {
324 const glu::ShaderProgram &shader = (passNdx == 0) ? (*m_shader0) : (*m_shader1);
325 const glw::GLint positionLoc = gl.getAttribLocation(shader.getProgram(), "a_input");
326 const glw::GLint colorLoc = gl.getUniformLocation(shader.getProgram(), "u_color");
327 const tcu::Vec4 red = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
328 const tcu::Vec4 green = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
329 const tcu::Vec4 color = (passNdx == 0) ? (red) : (green);
330 const glw::GLenum depthFunc = (passNdx == 0) ? (GL_ALWAYS) : (GL_EQUAL);
331 const char *const depthFuncStr = (passNdx == 0) ? ("GL_ALWAYS") : ("GL_EQUAL");
332 const char *const colorStr = (passNdx == 0) ? ("red - purple") : ("green");
333
334 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing Z-test pattern using shader " << (passNdx + 1)
335 << ". Primitive color: " << colorStr << ". DepthFunc: " << depthFuncStr
336 << tcu::TestLog::EndMessage;
337
338 gl.useProgram(shader.getProgram());
339 gl.uniform4fv(colorLoc, 1, color.getPtr());
340 gl.depthFunc(depthFunc);
341 gl.enableVertexAttribArray(positionLoc);
342 gl.vertexAttribPointer(positionLoc, 4, GL_FLOAT, GL_FALSE, sizeof(tcu::Vec4), DE_NULL);
343 gl.drawArrays(GL_TRIANGLES, m_verticesInPattern,
344 m_verticesInPattern); // !< buffer contains 2 m_verticesInPattern-sized patterns
345 gl.disableVertexAttribArray(positionLoc);
346 GLU_EXPECT_NO_ERROR(gl.getError(), "draw pass");
347 }
348
349 // Read result
350 glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess());
351
352 // Check there are no red pixels
353 m_testCtx.getLog() << tcu::TestLog::Message
354 << "Verifying output. Expecting only green or background colored pixels."
355 << tcu::TestLog::EndMessage;
356 error |= !checkImage(resultSurface);
357 }
358
359 // Report result
360 if (error)
361 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Detected variance between two invariant values");
362 else
363 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
364
365 return STOP;
366 }
367
checkImage(const tcu::Surface & surface) const368 bool InvarianceTest::checkImage(const tcu::Surface &surface) const
369 {
370 const tcu::IVec4 okColor = tcu::IVec4(0, 255, 0, 255);
371 const tcu::RGBA errColor = tcu::RGBA(255, 0, 0, 255);
372 bool error = false;
373 tcu::Surface errorMask(m_renderSize, m_renderSize);
374
375 tcu::clear(errorMask.getAccess(), okColor);
376
377 for (int y = 0; y < m_renderSize; ++y)
378 for (int x = 0; x < m_renderSize; ++x)
379 {
380 const tcu::RGBA col = surface.getPixel(x, y);
381
382 if (col.getRed() != 0)
383 {
384 errorMask.setPixel(x, y, errColor);
385 error = true;
386 }
387 }
388
389 // report error
390 if (error)
391 {
392 m_testCtx.getLog() << tcu::TestLog::Message
393 << "Invalid pixels found (fragments from first render pass found). Variance detected."
394 << tcu::TestLog::EndMessage;
395 m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
396 << tcu::TestLog::Image("Result", "Result", surface)
397 << tcu::TestLog::Image("Error mask", "Error mask", errorMask) << tcu::TestLog::EndImageSet;
398
399 return false;
400 }
401 else
402 {
403 m_testCtx.getLog() << tcu::TestLog::Message << "No variance found." << tcu::TestLog::EndMessage;
404 m_testCtx.getLog() << tcu::TestLog::ImageSet("Results", "Result verification")
405 << tcu::TestLog::Image("Result", "Result", surface) << tcu::TestLog::EndImageSet;
406
407 return true;
408 }
409 }
410
411 class BasicInvarianceTest : public InvarianceTest
412 {
413 public:
414 BasicInvarianceTest(Context &ctx, const char *name, const char *desc, const std::string &vertexShader1,
415 const std::string &vertexShader2);
416 ShaderPair genShaders(void) const;
417
418 private:
419 const std::string m_vertexShader1;
420 const std::string m_vertexShader2;
421 const std::string m_fragmentShader;
422 static const char *const s_basicFragmentShader;
423 };
424
425 const char *const BasicInvarianceTest::s_basicFragmentShader =
426 "uniform mediump vec4 u_color;\n"
427 "varying mediump vec4 v_unrelated;\n"
428 "void main ()\n"
429 "{\n"
430 " mediump float blue = dot(v_unrelated, vec4(1.0, 1.0, 1.0, 1.0));\n"
431 " gl_FragColor = vec4(u_color.r, u_color.g, blue, u_color.a);\n"
432 "}\n";
433
BasicInvarianceTest(Context & ctx,const char * name,const char * desc,const std::string & vertexShader1,const std::string & vertexShader2)434 BasicInvarianceTest::BasicInvarianceTest(Context &ctx, const char *name, const char *desc,
435 const std::string &vertexShader1, const std::string &vertexShader2)
436 : InvarianceTest(ctx, name, desc)
437 , m_vertexShader1(vertexShader1)
438 , m_vertexShader2(vertexShader2)
439 , m_fragmentShader(s_basicFragmentShader)
440 {
441 }
442
genShaders(void) const443 BasicInvarianceTest::ShaderPair BasicInvarianceTest::genShaders(void) const
444 {
445 ShaderPair retVal;
446
447 retVal.vertexShaderSource0 = m_vertexShader1;
448 retVal.vertexShaderSource1 = m_vertexShader2;
449 retVal.fragmentShaderSource0 = m_fragmentShader;
450 retVal.fragmentShaderSource1 = m_fragmentShader;
451
452 return retVal;
453 }
454
455 } // namespace
456
ShaderInvarianceTests(Context & context)457 ShaderInvarianceTests::ShaderInvarianceTests(Context &context)
458 : TestCaseGroup(context, "invariance", "Invariance tests")
459 {
460 }
461
~ShaderInvarianceTests(void)462 ShaderInvarianceTests::~ShaderInvarianceTests(void)
463 {
464 }
465
init(void)466 void ShaderInvarianceTests::init(void)
467 {
468 static const struct PrecisionCase
469 {
470 glu::Precision prec;
471 const char *name;
472
473 // set literals in the glsl to be in the representable range
474 const char *highValue; // !< highValue < maxValue
475 const char *invHighValue;
476 const char *mediumValue; // !< mediumValue^2 < maxValue
477 const char *lowValue; // !< lowValue^4 < maxValue
478 const char *invlowValue;
479 int loopIterations;
480 int loopPartialIterations;
481 int loopNormalizationExponent;
482 const char *loopNormalizationConstantLiteral;
483 const char *loopMultiplier;
484 const char *sumLoopNormalizationConstantLiteral;
485 } precisions[] = {
486 {glu::PRECISION_HIGHP, "highp", "1.0e20", "1.0e-20", "1.0e14", "1.0e9", "1.0e-9", 14, 11, 2, "1.0e4", "1.9",
487 "1.0e3"},
488 {glu::PRECISION_MEDIUMP, "mediump", "1.0e4", "1.0e-4", "1.0e2", "1.0e1", "1.0e-1", 13, 11, 2, "1.0e4", "1.9",
489 "1.0e3"},
490 {glu::PRECISION_LOWP, "lowp", "0.9", "1.1", "1.1", "1.15", "0.87", 6, 2, 0, "2.0", "1.1", "1.0"},
491 };
492
493 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); ++precNdx)
494 {
495 const char *const precisionName = precisions[precNdx].name;
496 const glu::Precision precision = precisions[precNdx].prec;
497 tcu::TestCaseGroup *const group =
498 new tcu::TestCaseGroup(m_testCtx, precisionName, "Invariance tests using the given precision.");
499
500 const FormatArgumentList args =
501 FormatArgumentList() << FormatArgument("VERSION", "") << FormatArgument("IN", "attribute")
502 << FormatArgument("OUT", "varying") << FormatArgument("IN_PREC", precisionName)
503 << FormatArgument("HIGH_VALUE", de::toString(precisions[precNdx].highValue))
504 << FormatArgument("HIGH_VALUE_INV", de::toString(precisions[precNdx].invHighValue))
505 << FormatArgument("MEDIUM_VALUE", de::toString(precisions[precNdx].mediumValue))
506 << FormatArgument("LOW_VALUE", de::toString(precisions[precNdx].lowValue))
507 << FormatArgument("LOW_VALUE_INV", de::toString(precisions[precNdx].invlowValue))
508 << FormatArgument("LOOP_ITERS", de::toString(precisions[precNdx].loopIterations))
509 << FormatArgument("LOOP_ITERS_PARTIAL",
510 de::toString(precisions[precNdx].loopPartialIterations))
511 << FormatArgument("LOOP_NORM_FRACT_EXP",
512 de::toString(precisions[precNdx].loopNormalizationExponent))
513 << FormatArgument("LOOP_NORM_LITERAL",
514 precisions[precNdx].loopNormalizationConstantLiteral)
515 << FormatArgument("LOOP_MULTIPLIER", precisions[precNdx].loopMultiplier)
516 << FormatArgument("SUM_LOOP_NORM_LITERAL",
517 precisions[precNdx].sumLoopNormalizationConstantLiteral);
518
519 addChild(group);
520
521 // subexpression cases
522 {
523 // First shader shares "${HIGH_VALUE}*a_input.x*a_input.xxxx + ${HIGH_VALUE}*a_input.y*a_input.yyyy" with unrelated output variable. Reordering might result in accuracy loss
524 // due to the high exponent. In the second shader, the high exponent may be removed during compilation.
525
526 group->addChild(new BasicInvarianceTest(
527 m_context, "common_subexpression_0", "Shader shares a subexpression with an unrelated variable.",
528 formatGLSL(
529 "${VERSION}"
530 "${IN} ${IN_PREC} vec4 a_input;\n"
531 "${OUT} mediump vec4 v_unrelated;\n"
532 "invariant gl_Position;\n"
533 "void main ()\n"
534 "{\n"
535 " v_unrelated = a_input.xzxz + (${HIGH_VALUE}*a_input.x*a_input.xxxx + "
536 "${HIGH_VALUE}*a_input.y*a_input.yyyy) * (1.08 * a_input.zyzy * a_input.xzxz) * ${HIGH_VALUE_INV} "
537 "* (a_input.z * a_input.zzxz - a_input.z * a_input.zzxz) + (${HIGH_VALUE}*a_input.x*a_input.xxxx + "
538 "${HIGH_VALUE}*a_input.y*a_input.yyyy) / ${HIGH_VALUE};\n"
539 " gl_Position = a_input + (${HIGH_VALUE}*a_input.x*a_input.xxxx + "
540 "${HIGH_VALUE}*a_input.y*a_input.yyyy) * ${HIGH_VALUE_INV};\n"
541 "}\n",
542 args),
543 formatGLSL("${VERSION}"
544 "${IN} ${IN_PREC} vec4 a_input;\n"
545 "${OUT} mediump vec4 v_unrelated;\n"
546 "invariant gl_Position;\n"
547 "void main ()\n"
548 "{\n"
549 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
550 " gl_Position = a_input + (${HIGH_VALUE}*a_input.x*a_input.xxxx + "
551 "${HIGH_VALUE}*a_input.y*a_input.yyyy) * ${HIGH_VALUE_INV};\n"
552 "}\n",
553 args)));
554
555 // In the first shader, the unrelated variable "d" has mathematically the same expression as "e", but the different
556 // order of calculation might cause different results.
557
558 group->addChild(new BasicInvarianceTest(
559 m_context, "common_subexpression_1", "Shader shares a subexpression with an unrelated variable.",
560 formatGLSL("${VERSION}"
561 "${IN} ${IN_PREC} vec4 a_input;\n"
562 "${OUT} mediump vec4 v_unrelated;\n"
563 "invariant gl_Position;\n"
564 "void main ()\n"
565 "{\n"
566 " ${IN_PREC} vec4 a = ${HIGH_VALUE} * a_input.zzxx + a_input.xzxy - ${HIGH_VALUE} * "
567 "a_input.zzxx;\n"
568 " ${IN_PREC} vec4 b = ${HIGH_VALUE} * a_input.zzxx;\n"
569 " ${IN_PREC} vec4 c = b - ${HIGH_VALUE} * a_input.zzxx + a_input.xzxy;\n"
570 " ${IN_PREC} vec4 d = (${LOW_VALUE} * a_input.yzxx) * (${LOW_VALUE} * a_input.yzzw) * "
571 "(1.1*${LOW_VALUE_INV} * a_input.yzxx) * (${LOW_VALUE_INV} * a_input.xzzy);\n"
572 " ${IN_PREC} vec4 e = ((${LOW_VALUE} * a_input.yzxx) * (1.1*${LOW_VALUE_INV} * "
573 "a_input.yzxx)) * ((${LOW_VALUE_INV} * a_input.xzzy) * (${LOW_VALUE} * a_input.yzzw));\n"
574 " v_unrelated = a + b + c + d + e;\n"
575 " gl_Position = a_input + fract(c) + e;\n"
576 "}\n",
577 args),
578 formatGLSL("${VERSION}"
579 "${IN} ${IN_PREC} vec4 a_input;\n"
580 "${OUT} mediump vec4 v_unrelated;\n"
581 "invariant gl_Position;\n"
582 "void main ()\n"
583 "{\n"
584 " ${IN_PREC} vec4 b = ${HIGH_VALUE} * a_input.zzxx;\n"
585 " ${IN_PREC} vec4 c = b - ${HIGH_VALUE} * a_input.zzxx + a_input.xzxy;\n"
586 " ${IN_PREC} vec4 e = ((${LOW_VALUE} * a_input.yzxx) * (1.1*${LOW_VALUE_INV} * "
587 "a_input.yzxx)) * ((${LOW_VALUE_INV} * a_input.xzzy) * (${LOW_VALUE} * a_input.yzzw));\n"
588 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
589 " gl_Position = a_input + fract(c) + e;\n"
590 "}\n",
591 args)));
592
593 // Intermediate values used by an unrelated output variable
594
595 group->addChild(new BasicInvarianceTest(
596 m_context, "common_subexpression_2", "Shader shares a subexpression with an unrelated variable.",
597 formatGLSL("${VERSION}"
598 "${IN} ${IN_PREC} vec4 a_input;\n"
599 "${OUT} mediump vec4 v_unrelated;\n"
600 "invariant gl_Position;\n"
601 "void main ()\n"
602 "{\n"
603 " ${IN_PREC} vec4 a = ${MEDIUM_VALUE} * (a_input.xxxx + a_input.yyyy);\n"
604 " ${IN_PREC} vec4 b = (${MEDIUM_VALUE} * (a_input.xxxx + a_input.yyyy)) * "
605 "(${MEDIUM_VALUE} * (a_input.xxxx + a_input.yyyy)) / ${MEDIUM_VALUE} / ${MEDIUM_VALUE};\n"
606 " ${IN_PREC} vec4 c = a * a;\n"
607 " ${IN_PREC} vec4 d = c / ${MEDIUM_VALUE} / ${MEDIUM_VALUE};\n"
608 " v_unrelated = a + b + c + d;\n"
609 " gl_Position = a_input + d;\n"
610 "}\n",
611 args),
612 formatGLSL("${VERSION}"
613 "${IN} ${IN_PREC} vec4 a_input;\n"
614 "${OUT} mediump vec4 v_unrelated;\n"
615 "invariant gl_Position;\n"
616 "void main ()\n"
617 "{\n"
618 " ${IN_PREC} vec4 a = ${MEDIUM_VALUE} * (a_input.xxxx + a_input.yyyy);\n"
619 " ${IN_PREC} vec4 c = a * a;\n"
620 " ${IN_PREC} vec4 d = c / ${MEDIUM_VALUE} / ${MEDIUM_VALUE};\n"
621 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
622 " gl_Position = a_input + d;\n"
623 "}\n",
624 args)));
625
626 // Invariant value can be calculated using unrelated value
627
628 group->addChild(new BasicInvarianceTest(m_context, "common_subexpression_3",
629 "Shader shares a subexpression with an unrelated variable.",
630 formatGLSL("${VERSION}"
631 "${IN} ${IN_PREC} vec4 a_input;\n"
632 "${OUT} mediump vec4 v_unrelated;\n"
633 "invariant gl_Position;\n"
634 "void main ()\n"
635 "{\n"
636 " ${IN_PREC} float x = a_input.x * 0.2;\n"
637 " ${IN_PREC} vec4 a = a_input.xxyx * 0.7;\n"
638 " ${IN_PREC} vec4 b = a_input.yxyz * 0.7;\n"
639 " ${IN_PREC} vec4 c = a_input.zxyx * 0.5;\n"
640 " ${IN_PREC} vec4 f = x*a + x*b + x*c;\n"
641 " v_unrelated = f;\n"
642 " ${IN_PREC} vec4 g = x * (a + b + c);\n"
643 " gl_Position = a_input + g;\n"
644 "}\n",
645 args),
646 formatGLSL("${VERSION}"
647 "${IN} ${IN_PREC} vec4 a_input;\n"
648 "${OUT} mediump vec4 v_unrelated;\n"
649 "invariant gl_Position;\n"
650 "void main ()\n"
651 "{\n"
652 " ${IN_PREC} float x = a_input.x * 0.2;\n"
653 " ${IN_PREC} vec4 a = a_input.xxyx * 0.7;\n"
654 " ${IN_PREC} vec4 b = a_input.yxyz * 0.7;\n"
655 " ${IN_PREC} vec4 c = a_input.zxyx * 0.5;\n"
656 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
657 " ${IN_PREC} vec4 g = x * (a + b + c);\n"
658 " gl_Position = a_input + g;\n"
659 "}\n",
660 args)));
661 }
662
663 // shared subexpression of different precision
664 {
665 for (int precisionOther = glu::PRECISION_LOWP; precisionOther != glu::PRECISION_LAST; ++precisionOther)
666 {
667 const char *const unrelatedPrec = glu::getPrecisionName((glu::Precision)precisionOther);
668 const glu::Precision minPrecision =
669 (precisionOther < (int)precision) ? ((glu::Precision)precisionOther) : (precision);
670 const char *const multiplierStr =
671 (minPrecision == glu::PRECISION_LOWP) ? ("0.8, 0.4, -0.2, 0.3") : ("1.0e1, 5.0e2, 2.0e2, 1.0");
672 const char *const normalizationStrUsed =
673 (minPrecision == glu::PRECISION_LOWP) ?
674 ("vec4(fract(used2).xyz, 0.0)") :
675 ("vec4(fract(used2 / 1.0e2).xyz - fract(used2 / 1.0e3).xyz, 0.0)");
676 const char *const normalizationStrUnrelated =
677 (minPrecision == glu::PRECISION_LOWP) ?
678 ("vec4(fract(unrelated2).xyz, 0.0)") :
679 ("vec4(fract(unrelated2 / 1.0e2).xyz - fract(unrelated2 / 1.0e3).xyz, 0.0)");
680
681 group->addChild(new BasicInvarianceTest(
682 m_context, ("subexpression_precision_" + std::string(unrelatedPrec)).c_str(),
683 "Shader shares subexpression of different precision with an unrelated variable.",
684 formatGLSL(
685 "${VERSION}"
686 "${IN} ${IN_PREC} vec4 a_input;\n"
687 "${OUT} ${UNRELATED_PREC} vec4 v_unrelated;\n"
688 "invariant gl_Position;\n"
689 "void main ()\n"
690 "{\n"
691 " ${UNRELATED_PREC} vec4 unrelated0 = a_input + vec4(0.1, 0.2, 0.3, 0.4);\n"
692 " ${UNRELATED_PREC} vec4 unrelated1 = vec4(${MULTIPLIER}) * unrelated0.xywz + unrelated0;\n"
693 " ${UNRELATED_PREC} vec4 unrelated2 = refract(unrelated1, unrelated0, distance(unrelated0, "
694 "unrelated1));\n"
695 " v_unrelated = a_input + 0.02 * ${NORMALIZE_UNRELATED};\n"
696 " ${IN_PREC} vec4 used0 = a_input + vec4(0.1, 0.2, 0.3, 0.4);\n"
697 " ${IN_PREC} vec4 used1 = vec4(${MULTIPLIER}) * used0.xywz + used0;\n"
698 " ${IN_PREC} vec4 used2 = refract(used1, used0, distance(used0, used1));\n"
699 " gl_Position = a_input + 0.02 * ${NORMALIZE_USED};\n"
700 "}\n",
701 FormatArgumentList(args) << FormatArgument("UNRELATED_PREC", unrelatedPrec)
702 << FormatArgument("MULTIPLIER", multiplierStr)
703 << FormatArgument("NORMALIZE_USED", normalizationStrUsed)
704 << FormatArgument("NORMALIZE_UNRELATED", normalizationStrUnrelated)),
705 formatGLSL("${VERSION}"
706 "${IN} ${IN_PREC} vec4 a_input;\n"
707 "${OUT} ${UNRELATED_PREC} vec4 v_unrelated;\n"
708 "invariant gl_Position;\n"
709 "void main ()\n"
710 "{\n"
711 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
712 " ${IN_PREC} vec4 used0 = a_input + vec4(0.1, 0.2, 0.3, 0.4);\n"
713 " ${IN_PREC} vec4 used1 = vec4(${MULTIPLIER}) * used0.xywz + used0;\n"
714 " ${IN_PREC} vec4 used2 = refract(used1, used0, distance(used0, used1));\n"
715 " gl_Position = a_input + 0.02 * ${NORMALIZE_USED};\n"
716 "}\n",
717 FormatArgumentList(args)
718 << FormatArgument("UNRELATED_PREC", unrelatedPrec)
719 << FormatArgument("MULTIPLIER", multiplierStr)
720 << FormatArgument("NORMALIZE_USED", normalizationStrUsed)
721 << FormatArgument("NORMALIZE_UNRELATED", normalizationStrUnrelated))));
722 }
723 }
724
725 // loops
726 {
727 group->addChild(new BasicInvarianceTest(
728 m_context, "loop_0", "Invariant value set using a loop",
729 formatGLSL("${VERSION}"
730 "${IN} ${IN_PREC} vec4 a_input;\n"
731 "${OUT} highp vec4 v_unrelated;\n"
732 "invariant gl_Position;\n"
733 "void main ()\n"
734 "{\n"
735 " ${IN_PREC} vec4 value = a_input;\n"
736 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
737 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
738 " {\n"
739 " value *= ${LOOP_MULTIPLIER};\n"
740 " v_unrelated += value;\n"
741 " }\n"
742 " gl_Position = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
743 "}\n",
744 args),
745 formatGLSL("${VERSION}"
746 "${IN} ${IN_PREC} vec4 a_input;\n"
747 "${OUT} highp vec4 v_unrelated;\n"
748 "invariant gl_Position;\n"
749 "void main ()\n"
750 "{\n"
751 " ${IN_PREC} vec4 value = a_input;\n"
752 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
753 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
754 " {\n"
755 " value *= ${LOOP_MULTIPLIER};\n"
756 " }\n"
757 " gl_Position = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
758 "}\n",
759 args)));
760
761 group->addChild(new BasicInvarianceTest(
762 m_context, "loop_1", "Invariant value set using a loop",
763 formatGLSL("${VERSION}"
764 "${IN} ${IN_PREC} vec4 a_input;\n"
765 "${OUT} mediump vec4 v_unrelated;\n"
766 "invariant gl_Position;\n"
767 "void main ()\n"
768 "{\n"
769 " ${IN_PREC} vec4 value = a_input;\n"
770 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
771 " {\n"
772 " value *= ${LOOP_MULTIPLIER};\n"
773 " if (i == ${LOOP_ITERS_PARTIAL})\n"
774 " v_unrelated = value;\n"
775 " }\n"
776 " gl_Position = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
777 "}\n",
778 args),
779 formatGLSL("${VERSION}"
780 "${IN} ${IN_PREC} vec4 a_input;\n"
781 "${OUT} mediump vec4 v_unrelated;\n"
782 "invariant gl_Position;\n"
783 "void main ()\n"
784 "{\n"
785 " ${IN_PREC} vec4 value = a_input;\n"
786 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
787 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
788 " {\n"
789 " value *= ${LOOP_MULTIPLIER};\n"
790 " }\n"
791 " gl_Position = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
792 "}\n",
793 args)));
794
795 group->addChild(
796 new BasicInvarianceTest(m_context, "loop_2", "Invariant value set using a loop",
797 formatGLSL("${VERSION}"
798 "${IN} ${IN_PREC} vec4 a_input;\n"
799 "${OUT} mediump vec4 v_unrelated;\n"
800 "invariant gl_Position;\n"
801 "void main ()\n"
802 "{\n"
803 " ${IN_PREC} vec4 value = a_input;\n"
804 " v_unrelated = vec4(0.0, 0.0, -1.0, 1.0);\n"
805 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
806 " {\n"
807 " value *= ${LOOP_MULTIPLIER};\n"
808 " if (i == ${LOOP_ITERS_PARTIAL})\n"
809 " gl_Position = a_input + 0.05 * vec4(fract(value.xyz / "
810 "1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n"
811 " else\n"
812 " v_unrelated = value + a_input;\n"
813 " }\n"
814 "}\n",
815 args),
816 formatGLSL("${VERSION}"
817 "${IN} ${IN_PREC} vec4 a_input;\n"
818 "${OUT} mediump vec4 v_unrelated;\n"
819 "invariant gl_Position;\n"
820 "void main ()\n"
821 "{\n"
822 " ${IN_PREC} vec4 value = a_input;\n"
823 " v_unrelated = vec4(0.0, 0.0, -1.0, 1.0);\n"
824 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
825 " {\n"
826 " value *= ${LOOP_MULTIPLIER};\n"
827 " if (i == ${LOOP_ITERS_PARTIAL})\n"
828 " gl_Position = a_input + 0.05 * vec4(fract(value.xyz / "
829 "1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n"
830 " else\n"
831 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
832 " }\n"
833 "}\n",
834 args)));
835
836 group->addChild(new BasicInvarianceTest(
837 m_context, "loop_3", "Invariant value set using a loop",
838 formatGLSL(
839 "${VERSION}"
840 "${IN} ${IN_PREC} vec4 a_input;\n"
841 "${OUT} mediump vec4 v_unrelated;\n"
842 "invariant gl_Position;\n"
843 "void main ()\n"
844 "{\n"
845 " ${IN_PREC} vec4 value = a_input;\n"
846 " gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n"
847 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
848 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
849 " {\n"
850 " value *= ${LOOP_MULTIPLIER};\n"
851 " gl_Position += vec4(value.xyz / ${SUM_LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
852 " v_unrelated = gl_Position.xyzx * a_input;\n"
853 " }\n"
854 "}\n",
855 args),
856 formatGLSL(
857 "${VERSION}"
858 "${IN} ${IN_PREC} vec4 a_input;\n"
859 "${OUT} mediump vec4 v_unrelated;\n"
860 "invariant gl_Position;\n"
861 "void main ()\n"
862 "{\n"
863 " ${IN_PREC} vec4 value = a_input;\n"
864 " gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n"
865 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
866 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
867 " {\n"
868 " value *= ${LOOP_MULTIPLIER};\n"
869 " gl_Position += vec4(value.xyz / ${SUM_LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
870 " }\n"
871 "}\n",
872 args)));
873
874 group->addChild(new BasicInvarianceTest(
875 m_context, "loop_4", "Invariant value set using a loop",
876 formatGLSL(
877 "${VERSION}"
878 "${IN} ${IN_PREC} vec4 a_input;\n"
879 "${OUT} mediump vec4 v_unrelated;\n"
880 "invariant gl_Position;\n"
881 "void main ()\n"
882 "{\n"
883 " ${IN_PREC} vec4 position = vec4(0.0, 0.0, 0.0, 0.0);\n"
884 " ${IN_PREC} vec4 value1 = a_input;\n"
885 " ${IN_PREC} vec4 value2 = a_input;\n"
886 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
887 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
888 " {\n"
889 " value1 *= ${LOOP_MULTIPLIER};\n"
890 " v_unrelated = v_unrelated*1.3 + a_input.xyzx * value1.xyxw;\n"
891 " }\n"
892 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
893 " {\n"
894 " value2 *= ${LOOP_MULTIPLIER};\n"
895 " position = position*1.3 + a_input.xyzx * value2.xyxw;\n"
896 " }\n"
897 " gl_Position = a_input + 0.05 * vec4(fract(position.xyz / 1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n"
898 "}\n",
899 args),
900 formatGLSL(
901 "${VERSION}"
902 "${IN} ${IN_PREC} vec4 a_input;\n"
903 "${OUT} mediump vec4 v_unrelated;\n"
904 "invariant gl_Position;\n"
905 "void main ()\n"
906 "{\n"
907 " ${IN_PREC} vec4 position = vec4(0.0, 0.0, 0.0, 0.0);\n"
908 " ${IN_PREC} vec4 value2 = a_input;\n"
909 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
910 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
911 " {\n"
912 " value2 *= ${LOOP_MULTIPLIER};\n"
913 " position = position*1.3 + a_input.xyzx * value2.xyxw;\n"
914 " }\n"
915 " gl_Position = a_input + 0.05 * vec4(fract(position.xyz / 1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n"
916 "}\n",
917 args)));
918 }
919 }
920 }
921
922 } // namespace Functional
923 } // namespace gles2
924 } // namespace deqp
925