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