1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Invariance tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es3fShaderInvarianceTests.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 gles3
43 {
44 namespace Functional
45 {
46 namespace
47 {
48
49 class FormatArgumentList;
50
genRandomVector(de::Random & rnd)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
FormatArgument(const char * name,const std::string & value)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
FormatArgumentList(void)93 FormatArgumentList::FormatArgumentList (void)
94 {
95 }
96
operator <<(const FormatArgument & arg)97 FormatArgumentList& FormatArgumentList::operator<< (const FormatArgument& arg)
98 {
99 m_formatArguments[arg.m_name] = arg.m_value;
100 return *this;
101 }
102
getArguments(void) const103 const std::map<std::string, std::string>& FormatArgumentList::getArguments (void) const
104 {
105 return m_formatArguments;
106 }
107
formatGLSL(const char * templateString,const FormatArgumentList & args)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
InvarianceTest(Context & ctx,const char * name,const char * desc)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
~InvarianceTest(void)163 InvarianceTest::~InvarianceTest (void)
164 {
165 deinit();
166 }
167
init(void)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
deinit(void)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
iterate(void)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
checkImage(const tcu::Surface & surface) const356 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 BasicInvarianceTest (Context& ctx, const char* name, const char* desc, const std::string& vertexShader1, const std::string& vertexShader2, const std::string& fragmentShader);
406 ShaderPair genShaders (void) const;
407
408 private:
409 const std::string m_vertexShader1;
410 const std::string m_vertexShader2;
411 const std::string m_fragmentShader;
412 static const char* const s_basicFragmentShader;
413 };
414
415 const char* const BasicInvarianceTest::s_basicFragmentShader = "#version 300 es\n"
416 "layout(location = 0) out mediump vec4 fragColor;\n"
417 "uniform mediump vec4 u_color;\n"
418 "in mediump vec4 v_unrelated;\n"
419 "void main ()\n"
420 "{\n"
421 " mediump float blue = dot(v_unrelated, vec4(1.0, 1.0, 1.0, 1.0));\n"
422 " fragColor = vec4(u_color.r, u_color.g, blue, u_color.a);\n"
423 "}\n";
424
BasicInvarianceTest(Context & ctx,const char * name,const char * desc,const std::string & vertexShader1,const std::string & vertexShader2)425 BasicInvarianceTest::BasicInvarianceTest (Context& ctx, const char* name, const char* desc, const std::string& vertexShader1, const std::string& vertexShader2)
426 : InvarianceTest (ctx, name, desc)
427 , m_vertexShader1 (vertexShader1)
428 , m_vertexShader2 (vertexShader2)
429 , m_fragmentShader (s_basicFragmentShader)
430 {
431 }
432
BasicInvarianceTest(Context & ctx,const char * name,const char * desc,const std::string & vertexShader1,const std::string & vertexShader2,const std::string & fragmentShader)433 BasicInvarianceTest::BasicInvarianceTest (Context& ctx, const char* name, const char* desc, const std::string& vertexShader1, const std::string& vertexShader2, const std::string& fragmentShader)
434 : InvarianceTest (ctx, name, desc)
435 , m_vertexShader1 (vertexShader1)
436 , m_vertexShader2 (vertexShader2)
437 , m_fragmentShader (fragmentShader)
438 {
439 }
440
genShaders(void) const441 BasicInvarianceTest::ShaderPair BasicInvarianceTest::genShaders (void) const
442 {
443 ShaderPair retVal;
444
445 retVal.vertexShaderSource0 = m_vertexShader1;
446 retVal.vertexShaderSource1 = m_vertexShader2;
447 retVal.fragmentShaderSource0 = m_fragmentShader;
448 retVal.fragmentShaderSource1 = m_fragmentShader;
449
450 return retVal;
451 }
452
453 } // anonymous
454
ShaderInvarianceTests(Context & context)455 ShaderInvarianceTests::ShaderInvarianceTests (Context& context)
456 : TestCaseGroup(context, "invariance", "Invariance tests")
457 {
458 }
459
~ShaderInvarianceTests(void)460 ShaderInvarianceTests::~ShaderInvarianceTests (void)
461 {
462 }
463
init(void)464 void ShaderInvarianceTests::init (void)
465 {
466 static const struct PrecisionCase
467 {
468 glu::Precision prec;
469 const char* name;
470
471 // set literals in the glsl to be in the representable range
472 const char* highValue; // !< highValue < maxValue
473 const char* invHighValue;
474 const char* mediumValue; // !< mediumValue^2 < maxValue
475 const char* lowValue; // !< lowValue^4 < maxValue
476 const char* invlowValue;
477 int loopIterations;
478 int loopPartialIterations;
479 int loopNormalizationExponent;
480 const char* loopNormalizationConstantLiteral;
481 const char* loopMultiplier;
482 const char* sumLoopNormalizationConstantLiteral;
483 } precisions[] =
484 {
485 { 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" },
486 { 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" },
487 { glu::PRECISION_LOWP, "lowp", "0.9", "1.1", "1.1", "1.15", "0.87", 6, 2, 0, "2.0", "1.1", "1.0" },
488 };
489
490 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); ++precNdx)
491 {
492 const char* const precisionName = precisions[precNdx].name;
493 const glu::Precision precision = precisions[precNdx].prec;
494 tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, precisionName, "Invariance tests using the given precision.");
495
496 const FormatArgumentList args = FormatArgumentList()
497 << FormatArgument("VERSION", "#version 300 es\n")
498 << FormatArgument("IN", "in")
499 << FormatArgument("OUT", "out")
500 << FormatArgument("IN_PREC", precisionName)
501 << FormatArgument("HIGH_VALUE", de::toString(precisions[precNdx].highValue))
502 << FormatArgument("HIGH_VALUE_INV", de::toString(precisions[precNdx].invHighValue))
503 << FormatArgument("MEDIUM_VALUE", de::toString(precisions[precNdx].mediumValue))
504 << FormatArgument("LOW_VALUE", de::toString(precisions[precNdx].lowValue))
505 << FormatArgument("LOW_VALUE_INV", de::toString(precisions[precNdx].invlowValue))
506 << FormatArgument("LOOP_ITERS", de::toString(precisions[precNdx].loopIterations))
507 << FormatArgument("LOOP_ITERS_PARTIAL", de::toString(precisions[precNdx].loopPartialIterations))
508 << FormatArgument("LOOP_NORM_FRACT_EXP", de::toString(precisions[precNdx].loopNormalizationExponent))
509 << FormatArgument("LOOP_NORM_LITERAL", precisions[precNdx].loopNormalizationConstantLiteral)
510 << FormatArgument("LOOP_MULTIPLIER", precisions[precNdx].loopMultiplier)
511 << FormatArgument("SUM_LOOP_NORM_LITERAL", precisions[precNdx].sumLoopNormalizationConstantLiteral);
512
513 addChild(group);
514
515 // subexpression cases
516 {
517 // 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
518 // due to the high exponent. In the second shader, the high exponent may be removed during compilation.
519
520 group->addChild(new BasicInvarianceTest(m_context, "common_subexpression_0", "Shader shares a subexpression with an unrelated variable.",
521 formatGLSL( "${VERSION}"
522 "${IN} ${IN_PREC} vec4 a_input;\n"
523 "${OUT} mediump vec4 v_unrelated;\n"
524 "invariant gl_Position;\n"
525 "void main ()\n"
526 "{\n"
527 " 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"
528 " gl_Position = a_input + (${HIGH_VALUE}*a_input.x*a_input.xxxx + ${HIGH_VALUE}*a_input.y*a_input.yyyy) * ${HIGH_VALUE_INV};\n"
529 "}\n", args),
530 formatGLSL( "${VERSION}"
531 "${IN} ${IN_PREC} vec4 a_input;\n"
532 "${OUT} mediump vec4 v_unrelated;\n"
533 "invariant gl_Position;\n"
534 "void main ()\n"
535 "{\n"
536 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
537 " gl_Position = a_input + (${HIGH_VALUE}*a_input.x*a_input.xxxx + ${HIGH_VALUE}*a_input.y*a_input.yyyy) * ${HIGH_VALUE_INV};\n"
538 "}\n", args)));
539
540 // In the first shader, the unrelated variable "d" has mathematically the same expression as "e", but the different
541 // order of calculation might cause different results.
542
543 group->addChild(new BasicInvarianceTest(m_context, "common_subexpression_1", "Shader shares a subexpression with an unrelated variable.",
544 formatGLSL( "${VERSION}"
545 "${IN} ${IN_PREC} vec4 a_input;\n"
546 "${OUT} mediump vec4 v_unrelated;\n"
547 "invariant gl_Position;\n"
548 "void main ()\n"
549 "{\n"
550 " ${IN_PREC} vec4 a = ${HIGH_VALUE} * a_input.zzxx + a_input.xzxy - ${HIGH_VALUE} * a_input.zzxx;\n"
551 " ${IN_PREC} vec4 b = ${HIGH_VALUE} * a_input.zzxx;\n"
552 " ${IN_PREC} vec4 c = b - ${HIGH_VALUE} * a_input.zzxx + a_input.xzxy;\n"
553 " ${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"
554 " ${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"
555 " v_unrelated = a + b + c + d + e;\n"
556 " gl_Position = a_input + fract(c) + e;\n"
557 "}\n", args),
558 formatGLSL( "${VERSION}"
559 "${IN} ${IN_PREC} vec4 a_input;\n"
560 "${OUT} mediump vec4 v_unrelated;\n"
561 "invariant gl_Position;\n"
562 "void main ()\n"
563 "{\n"
564 " ${IN_PREC} vec4 b = ${HIGH_VALUE} * a_input.zzxx;\n"
565 " ${IN_PREC} vec4 c = b - ${HIGH_VALUE} * a_input.zzxx + a_input.xzxy;\n"
566 " ${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"
567 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
568 " gl_Position = a_input + fract(c) + e;\n"
569 "}\n", args)));
570
571 // Intermediate values used by an unrelated output variable
572
573 group->addChild(new BasicInvarianceTest(m_context, "common_subexpression_2", "Shader shares a subexpression with an unrelated variable.",
574 formatGLSL( "${VERSION}"
575 "${IN} ${IN_PREC} vec4 a_input;\n"
576 "${OUT} mediump vec4 v_unrelated;\n"
577 "invariant gl_Position;\n"
578 "void main ()\n"
579 "{\n"
580 " ${IN_PREC} vec4 a = ${MEDIUM_VALUE} * (a_input.xxxx + a_input.yyyy);\n"
581 " ${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"
582 " ${IN_PREC} vec4 c = a * a;\n"
583 " ${IN_PREC} vec4 d = c / ${MEDIUM_VALUE} / ${MEDIUM_VALUE};\n"
584 " v_unrelated = a + b + c + d;\n"
585 " gl_Position = a_input + d;\n"
586 "}\n", args),
587 formatGLSL( "${VERSION}"
588 "${IN} ${IN_PREC} vec4 a_input;\n"
589 "${OUT} mediump vec4 v_unrelated;\n"
590 "invariant gl_Position;\n"
591 "void main ()\n"
592 "{\n"
593 " ${IN_PREC} vec4 a = ${MEDIUM_VALUE} * (a_input.xxxx + a_input.yyyy);\n"
594 " ${IN_PREC} vec4 c = a * a;\n"
595 " ${IN_PREC} vec4 d = c / ${MEDIUM_VALUE} / ${MEDIUM_VALUE};\n"
596 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
597 " gl_Position = a_input + d;\n"
598 "}\n", args)));
599
600 // Invariant value can be calculated using unrelated value
601
602 group->addChild(new BasicInvarianceTest(m_context, "common_subexpression_3", "Shader shares a subexpression with an unrelated variable.",
603 formatGLSL( "${VERSION}"
604 "${IN} ${IN_PREC} vec4 a_input;\n"
605 "${OUT} mediump vec4 v_unrelated;\n"
606 "invariant gl_Position;\n"
607 "void main ()\n"
608 "{\n"
609 " ${IN_PREC} float x = a_input.x * 0.2;\n"
610 " ${IN_PREC} vec4 a = a_input.xxyx * 0.7;\n"
611 " ${IN_PREC} vec4 b = a_input.yxyz * 0.7;\n"
612 " ${IN_PREC} vec4 c = a_input.zxyx * 0.5;\n"
613 " ${IN_PREC} vec4 f = x*a + x*b + x*c;\n"
614 " v_unrelated = f;\n"
615 " ${IN_PREC} vec4 g = x * (a + b + c);\n"
616 " gl_Position = a_input + g;\n"
617 "}\n", args),
618 formatGLSL( "${VERSION}"
619 "${IN} ${IN_PREC} vec4 a_input;\n"
620 "${OUT} mediump vec4 v_unrelated;\n"
621 "invariant gl_Position;\n"
622 "void main ()\n"
623 "{\n"
624 " ${IN_PREC} float x = a_input.x * 0.2;\n"
625 " ${IN_PREC} vec4 a = a_input.xxyx * 0.7;\n"
626 " ${IN_PREC} vec4 b = a_input.yxyz * 0.7;\n"
627 " ${IN_PREC} vec4 c = a_input.zxyx * 0.5;\n"
628 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
629 " ${IN_PREC} vec4 g = x * (a + b + c);\n"
630 " gl_Position = a_input + g;\n"
631 "}\n", args)));
632 }
633
634 // shared subexpression of different precision
635 {
636 for (int precisionOther = glu::PRECISION_LOWP; precisionOther != glu::PRECISION_LAST; ++precisionOther)
637 {
638 const char* const unrelatedPrec = glu::getPrecisionName((glu::Precision)precisionOther);
639 const glu::Precision minPrecision = (precisionOther < (int)precision) ? ((glu::Precision)precisionOther) : (precision);
640 const char* const multiplierStr = (minPrecision == glu::PRECISION_LOWP) ? ("0.8, 0.4, -0.2, 0.3") : ("1.0e1, 5.0e2, 2.0e2, 1.0");
641 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)");
642 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)");
643
644 group->addChild(new BasicInvarianceTest(m_context, ("subexpression_precision_" + std::string(unrelatedPrec)).c_str(), "Shader shares subexpression of different precision with an unrelated variable.",
645 formatGLSL( "${VERSION}"
646 "${IN} ${IN_PREC} vec4 a_input;\n"
647 "${OUT} ${UNRELATED_PREC} vec4 v_unrelated;\n"
648 "invariant gl_Position;\n"
649 "void main ()\n"
650 "{\n"
651 " ${UNRELATED_PREC} vec4 unrelated0 = a_input + vec4(0.1, 0.2, 0.3, 0.4);\n"
652 " ${UNRELATED_PREC} vec4 unrelated1 = vec4(${MULTIPLIER}) * unrelated0.xywz + unrelated0;\n"
653 " ${UNRELATED_PREC} vec4 unrelated2 = refract(unrelated1, unrelated0, distance(unrelated0, unrelated1));\n"
654 " v_unrelated = a_input + 0.02 * ${NORMALIZE_UNRELATED};\n"
655 " ${IN_PREC} vec4 used0 = a_input + vec4(0.1, 0.2, 0.3, 0.4);\n"
656 " ${IN_PREC} vec4 used1 = vec4(${MULTIPLIER}) * used0.xywz + used0;\n"
657 " ${IN_PREC} vec4 used2 = refract(used1, used0, distance(used0, used1));\n"
658 " gl_Position = a_input + 0.02 * ${NORMALIZE_USED};\n"
659 "}\n", FormatArgumentList(args)
660 << FormatArgument("UNRELATED_PREC", unrelatedPrec)
661 << FormatArgument("MULTIPLIER", multiplierStr)
662 << FormatArgument("NORMALIZE_USED", normalizationStrUsed)
663 << FormatArgument("NORMALIZE_UNRELATED", normalizationStrUnrelated)),
664 formatGLSL( "${VERSION}"
665 "${IN} ${IN_PREC} vec4 a_input;\n"
666 "${OUT} ${UNRELATED_PREC} vec4 v_unrelated;\n"
667 "invariant gl_Position;\n"
668 "void main ()\n"
669 "{\n"
670 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
671 " ${IN_PREC} vec4 used0 = a_input + vec4(0.1, 0.2, 0.3, 0.4);\n"
672 " ${IN_PREC} vec4 used1 = vec4(${MULTIPLIER}) * used0.xywz + used0;\n"
673 " ${IN_PREC} vec4 used2 = refract(used1, used0, distance(used0, used1));\n"
674 " gl_Position = a_input + 0.02 * ${NORMALIZE_USED};\n"
675 "}\n", FormatArgumentList(args)
676 << FormatArgument("UNRELATED_PREC", unrelatedPrec)
677 << FormatArgument("MULTIPLIER", multiplierStr)
678 << FormatArgument("NORMALIZE_USED", normalizationStrUsed)
679 << FormatArgument("NORMALIZE_UNRELATED", normalizationStrUnrelated))));
680 }
681 }
682
683 // loops
684 {
685 group->addChild(new BasicInvarianceTest(m_context, "loop_0", "Invariant value set using a loop",
686 formatGLSL( "${VERSION}"
687 "${IN} ${IN_PREC} vec4 a_input;\n"
688 "${OUT} highp vec4 v_unrelated;\n"
689 "invariant gl_Position;\n"
690 "void main ()\n"
691 "{\n"
692 " ${IN_PREC} vec4 value = a_input;\n"
693 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
694 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
695 " {\n"
696 " value *= ${LOOP_MULTIPLIER};\n"
697 " v_unrelated += value;\n"
698 " }\n"
699 " gl_Position = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
700 "}\n", args),
701 formatGLSL( "${VERSION}"
702 "${IN} ${IN_PREC} vec4 a_input;\n"
703 "${OUT} highp vec4 v_unrelated;\n"
704 "invariant gl_Position;\n"
705 "void main ()\n"
706 "{\n"
707 " ${IN_PREC} vec4 value = a_input;\n"
708 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
709 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
710 " {\n"
711 " value *= ${LOOP_MULTIPLIER};\n"
712 " }\n"
713 " gl_Position = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
714 "}\n", args)));
715
716 group->addChild(new BasicInvarianceTest(m_context, "loop_1", "Invariant value set using a loop",
717 formatGLSL( "${VERSION}"
718 "${IN} ${IN_PREC} vec4 a_input;\n"
719 "${OUT} mediump vec4 v_unrelated;\n"
720 "invariant gl_Position;\n"
721 "void main ()\n"
722 "{\n"
723 " ${IN_PREC} vec4 value = a_input;\n"
724 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
725 " {\n"
726 " value *= ${LOOP_MULTIPLIER};\n"
727 " if (i == ${LOOP_ITERS_PARTIAL})\n"
728 " v_unrelated = value;\n"
729 " }\n"
730 " gl_Position = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
731 "}\n", args),
732 formatGLSL( "${VERSION}"
733 "${IN} ${IN_PREC} vec4 a_input;\n"
734 "${OUT} mediump vec4 v_unrelated;\n"
735 "invariant gl_Position;\n"
736 "void main ()\n"
737 "{\n"
738 " ${IN_PREC} vec4 value = a_input;\n"
739 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
740 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
741 " {\n"
742 " value *= ${LOOP_MULTIPLIER};\n"
743 " }\n"
744 " gl_Position = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
745 "}\n", args)));
746
747 group->addChild(new BasicInvarianceTest(m_context, "loop_2", "Invariant value set using a loop",
748 formatGLSL( "${VERSION}"
749 "${IN} ${IN_PREC} vec4 a_input;\n"
750 "${OUT} mediump vec4 v_unrelated;\n"
751 "invariant gl_Position;\n"
752 "void main ()\n"
753 "{\n"
754 " ${IN_PREC} vec4 value = a_input;\n"
755 " v_unrelated = vec4(0.0, 0.0, -1.0, 1.0);\n"
756 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
757 " {\n"
758 " value *= ${LOOP_MULTIPLIER};\n"
759 " if (i == ${LOOP_ITERS_PARTIAL})\n"
760 " gl_Position = a_input + 0.05 * vec4(fract(value.xyz / 1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n"
761 " else\n"
762 " v_unrelated = value + a_input;\n"
763 " }\n"
764 "}\n", args),
765 formatGLSL( "${VERSION}"
766 "${IN} ${IN_PREC} vec4 a_input;\n"
767 "${OUT} mediump vec4 v_unrelated;\n"
768 "invariant gl_Position;\n"
769 "void main ()\n"
770 "{\n"
771 " ${IN_PREC} vec4 value = a_input;\n"
772 " v_unrelated = vec4(0.0, 0.0, -1.0, 1.0);\n"
773 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
774 " {\n"
775 " value *= ${LOOP_MULTIPLIER};\n"
776 " if (i == ${LOOP_ITERS_PARTIAL})\n"
777 " gl_Position = a_input + 0.05 * vec4(fract(value.xyz / 1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n"
778 " else\n"
779 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
780 " }\n"
781 "}\n", args)));
782
783 group->addChild(new BasicInvarianceTest(m_context, "loop_3", "Invariant value set using a loop",
784 formatGLSL( "${VERSION}"
785 "${IN} ${IN_PREC} vec4 a_input;\n"
786 "${OUT} mediump vec4 v_unrelated;\n"
787 "invariant gl_Position;\n"
788 "void main ()\n"
789 "{\n"
790 " ${IN_PREC} vec4 value = a_input;\n"
791 " gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n"
792 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
793 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
794 " {\n"
795 " value *= ${LOOP_MULTIPLIER};\n"
796 " gl_Position += vec4(value.xyz / ${SUM_LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
797 " v_unrelated = gl_Position.xyzx * a_input;\n"
798 " }\n"
799 "}\n", args),
800 formatGLSL( "${VERSION}"
801 "${IN} ${IN_PREC} vec4 a_input;\n"
802 "${OUT} mediump vec4 v_unrelated;\n"
803 "invariant gl_Position;\n"
804 "void main ()\n"
805 "{\n"
806 " ${IN_PREC} vec4 value = a_input;\n"
807 " gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n"
808 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
809 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
810 " {\n"
811 " value *= ${LOOP_MULTIPLIER};\n"
812 " gl_Position += vec4(value.xyz / ${SUM_LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
813 " }\n"
814 "}\n", args)));
815
816 group->addChild(new BasicInvarianceTest(m_context, "loop_4", "Invariant value set using a loop",
817 formatGLSL( "${VERSION}"
818 "${IN} ${IN_PREC} vec4 a_input;\n"
819 "${OUT} mediump vec4 v_unrelated;\n"
820 "invariant gl_Position;\n"
821 "void main ()\n"
822 "{\n"
823 " ${IN_PREC} vec4 position = vec4(0.0, 0.0, 0.0, 0.0);\n"
824 " ${IN_PREC} vec4 value1 = a_input;\n"
825 " ${IN_PREC} vec4 value2 = a_input;\n"
826 " v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
827 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
828 " {\n"
829 " value1 *= ${LOOP_MULTIPLIER};\n"
830 " v_unrelated = v_unrelated*1.3 + a_input.xyzx * value1.xyxw;\n"
831 " }\n"
832 " for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
833 " {\n"
834 " value2 *= ${LOOP_MULTIPLIER};\n"
835 " position = position*1.3 + a_input.xyzx * value2.xyxw;\n"
836 " }\n"
837 " gl_Position = a_input + 0.05 * vec4(fract(position.xyz / 1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n"
838 "}\n", args),
839 formatGLSL( "${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 position = vec4(0.0, 0.0, 0.0, 0.0);\n"
846 " ${IN_PREC} vec4 value2 = a_input;\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 " value2 *= ${LOOP_MULTIPLIER};\n"
851 " position = position*1.3 + a_input.xyzx * value2.xyxw;\n"
852 " }\n"
853 " gl_Position = a_input + 0.05 * vec4(fract(position.xyz / 1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n"
854 "}\n", args)));
855 }
856 }
857 }
858
859 } // Functional
860 } // gles3
861 } // deqp
862