xref: /aosp_15_r20/external/deqp/modules/gles2/functional/es2fShaderInvarianceTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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> &params = 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