Fix missing dependency on sparse binds
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / shaderrender / vktShaderRenderInvarianceTests.cpp
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2018 Google Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Invariant decoration tests.
23  *//*--------------------------------------------------------------------*/
24
25 #include "vktShaderRenderInvarianceTests.hpp"
26 #include "vktShaderRender.hpp"
27 #include "tcuImageCompare.hpp"
28 #include "tcuStringTemplate.hpp"
29 #include "tcuTextureUtil.hpp"
30 #include "tcuTestLog.hpp"
31 #include "vktDrawUtil.hpp"
32 #include "deMath.h"
33 #include "deRandom.hpp"
34
35 using namespace vk;
36
37 namespace vkt
38 {
39 using namespace drawutil;
40
41 namespace sr
42 {
43
44 namespace
45 {
46
47 class FormatArgument
48 {
49 public:
50                                                 FormatArgument (const char* name, const std::string& value);
51
52 private:
53         friend class FormatArgumentList;
54
55         const char* const       m_name;
56         const std::string       m_value;
57 };
58
59 FormatArgument::FormatArgument (const char* name, const std::string& value)
60         : m_name        (name)
61         , m_value       (value)
62 {
63 }
64
65 class FormatArgumentList
66 {
67 public:
68                                                                                                 FormatArgumentList      (void);
69
70         FormatArgumentList&                                                     operator<<                      (const FormatArgument&);
71         const std::map<std::string, std::string>&       getArguments            (void) const;
72
73 private:
74         std::map<std::string, std::string>                      m_formatArguments;
75 };
76
77 FormatArgumentList::FormatArgumentList (void)
78 {
79 }
80
81 FormatArgumentList&     FormatArgumentList::operator<< (const FormatArgument& arg)
82 {
83         m_formatArguments[arg.m_name] = arg.m_value;
84         return *this;
85 }
86
87 const std::map<std::string, std::string>& FormatArgumentList::getArguments (void) const
88 {
89         return m_formatArguments;
90 }
91
92 static std::string formatGLSL(const char* templateString, const FormatArgumentList& args)
93 {
94         const std::map<std::string, std::string>& params = args.getArguments();
95
96         return tcu::StringTemplate(std::string(templateString)).specialize(params);
97 }
98
99 class InvarianceTest : public vkt::TestCase
100 {
101 public:
102                                                                 InvarianceTest(tcu::TestContext& ctx, const char* name, const char* desc, const std::string& vertexShader1, const std::string& vertexShader2, const std::string& fragmentShader = "");
103
104         void                                            initPrograms    (SourceCollections& sourceCollections) const override;
105         vkt::TestInstance*                      createInstance  (vkt::Context& context) const override;
106
107 private:
108         const std::string                       m_vertexShader1;
109         const std::string                       m_vertexShader2;
110         const std::string                       m_fragmentShader;
111 };
112
113 class InvarianceTestInstance : public vkt::TestInstance
114 {
115 public:
116                                                 InvarianceTestInstance(vkt::Context &context);
117         tcu::TestStatus         iterate(void) override;
118         bool                            checkImage(const tcu::ConstPixelBufferAccess& image) const;
119         const int                       m_renderSize = 256;
120 };
121
122  InvarianceTest::InvarianceTest(tcu::TestContext& ctx, const char* name, const char* desc, const std::string& vertexShader1, const std::string& vertexShader2, const std::string& fragmentShader)
123         : vkt::TestCase(ctx, name, desc)
124         , m_vertexShader1(vertexShader1)
125         , m_vertexShader2(vertexShader2)
126         , m_fragmentShader(fragmentShader)
127
128 {
129 }
130
131 void InvarianceTest::initPrograms(SourceCollections& sourceCollections) const
132 {
133         sourceCollections.glslSources.add("vertex1") << glu::VertexSource(m_vertexShader1);
134         sourceCollections.glslSources.add("vertex2") << glu::VertexSource(m_vertexShader2);
135         sourceCollections.glslSources.add("fragment") << glu::FragmentSource(m_fragmentShader);
136 }
137
138 vkt::TestInstance* InvarianceTest::createInstance(Context& context) const
139 {
140         return new InvarianceTestInstance(context);
141 }
142
143 InvarianceTestInstance::InvarianceTestInstance(vkt::Context &context)
144         : vkt::TestInstance(context)
145 {
146 }
147
148 static tcu::Vec4 genRandomVector(de::Random& rnd)
149 {
150         tcu::Vec4 retVal;
151
152         retVal.x() = rnd.getFloat(-1.0f, 1.0f);
153         retVal.y() = rnd.getFloat(-1.0f, 1.0f);
154         retVal.z() = rnd.getFloat(-1.0f, 1.0f);
155         retVal.w() = rnd.getFloat(0.2f, 1.0f);
156
157         return retVal;
158 }
159
160 struct ColorUniform
161 {
162         tcu::Vec4 color;
163 };
164
165 tcu::TestStatus InvarianceTestInstance::iterate(void)
166 {
167         const VkDevice                  device                  = m_context.getDevice();
168         const DeviceInterface&  vk                              = m_context.getDeviceInterface();
169         Allocator&                              allocator               = m_context.getDefaultAllocator();
170         tcu::TestLog&                   log                             = m_context.getTestContext().getLog();
171
172         const int                               numTriangles    = 72;
173         de::Random                              rnd                             (123);
174         std::vector<tcu::Vec4>  vertices                (numTriangles * 3 * 2);
175
176         {
177                 // Narrow triangle pattern
178                 for (int triNdx = 0; triNdx < numTriangles; ++triNdx)
179                 {
180                         const tcu::Vec4 vertex1 = genRandomVector(rnd);
181                         const tcu::Vec4 vertex2 = genRandomVector(rnd);
182                         const tcu::Vec4 vertex3 = vertex2 + genRandomVector(rnd) * 0.01f; // generate narrow triangles
183
184                         vertices[triNdx * 3 + 0] = vertex1;
185                         vertices[triNdx * 3 + 1] = vertex2;
186                         vertices[triNdx * 3 + 2] = vertex3;
187                 }
188
189                 // Normal triangle pattern
190                 for (int triNdx = 0; triNdx < numTriangles; ++triNdx)
191                 {
192                         vertices[(numTriangles + triNdx) * 3 + 0] = genRandomVector(rnd);
193                         vertices[(numTriangles + triNdx) * 3 + 1] = genRandomVector(rnd);
194                         vertices[(numTriangles + triNdx) * 3 + 2] = genRandomVector(rnd);
195                 }
196         }
197
198         Move<VkDescriptorSetLayout>             descriptorSetLayout;
199         Move<VkDescriptorPool>                  descriptorPool;
200         Move<VkBuffer>                                  uniformBuffer[2];
201         de::MovePtr<Allocation>                 uniformBufferAllocation[2];
202         Move<VkDescriptorSet>                   descriptorSet[2];
203         const tcu::Vec4                                 red             = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
204         const tcu::Vec4                                 green   = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
205
206         // Descriptors
207         {
208                 DescriptorSetLayoutBuilder      layoutBuilder;
209                 layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT);
210                 descriptorSetLayout = layoutBuilder.build(vk, device);
211                 descriptorPool = DescriptorPoolBuilder()
212                                 .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2u)
213                                 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 2u);
214
215                 const VkDescriptorSetAllocateInfo descriptorSetAllocInfo =
216                 {
217                         VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
218                         DE_NULL,
219                         *descriptorPool,
220                         1u,
221                         &descriptorSetLayout.get()
222                 };
223
224                 const VkBufferCreateInfo uniformBufferCreateInfo =
225                 {
226                         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,                                   // VkStructureType              sType
227                         DE_NULL,                                                                                                // const void*                  pNext
228                         (VkBufferCreateFlags)0,                                                                 // VkBufferCreateFlags  flags
229                         sizeof(ColorUniform),                                                                   // VkDeviceSize                 size
230                         VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,                                             // VkBufferUsageFlags   usage
231                         VK_SHARING_MODE_EXCLUSIVE,                                                              // VkSharingMode                sharingMode
232                         0u,                                                                                                             // deUint32                             queueFamilyIndexCount
233                         DE_NULL                                                                                                 // pQueueFamilyIndices
234                 };
235
236                 for (deUint32 passNdx = 0; passNdx < 2; ++passNdx)
237                 {
238                         uniformBuffer[passNdx]                          = createBuffer(vk, device, &uniformBufferCreateInfo, DE_NULL);
239                         uniformBufferAllocation[passNdx]        = allocator.allocate(getBufferMemoryRequirements(vk, device, *uniformBuffer[passNdx]), MemoryRequirement::HostVisible);
240                         VK_CHECK(vk.bindBufferMemory(device, *uniformBuffer[passNdx], uniformBufferAllocation[passNdx]->getMemory(), uniformBufferAllocation[passNdx]->getOffset()));
241
242                         {
243                                 ColorUniform* bufferData        = (ColorUniform*)(uniformBufferAllocation[passNdx]->getHostPtr());
244                                 bufferData->color                       = (passNdx == 0) ? (red) : (green);
245                                 flushAlloc(vk, device, *uniformBufferAllocation[passNdx]);
246                         }
247                         descriptorSet[passNdx] = allocateDescriptorSet(vk, device, &descriptorSetAllocInfo);
248
249                         const VkDescriptorBufferInfo bufferInfo =
250                         {
251                                 *uniformBuffer[passNdx],
252                                 0u,
253                                 VK_WHOLE_SIZE
254                         };
255
256                         DescriptorSetUpdateBuilder()
257                                 .writeSingle(*descriptorSet[passNdx], DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &bufferInfo)
258                                 .update(vk, device);
259                 }
260         }
261
262         // pick first available depth buffer format
263         const std::vector<VkFormat>     depthFormats    { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_D24_UNORM_S8_UINT };
264         VkFormat                                        depthFormat             = VK_FORMAT_UNDEFINED;
265         const InstanceInterface&        vki                             = m_context.getInstanceInterface();
266         const VkPhysicalDevice          vkPhysDevice    = m_context.getPhysicalDevice();
267         for (const auto& df : depthFormats)
268         {
269                 const VkFormatProperties        properties = getPhysicalDeviceFormatProperties(vki, vkPhysDevice, df);
270                 if ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
271                 {
272                         depthFormat = df;
273                         break;
274                 }
275         }
276         if(depthFormat == VK_FORMAT_UNDEFINED)
277                 return tcu::TestStatus::fail("There must be at least one depth depth format handled (Vulkan spec 37.3, table 65)");
278
279         FrameBufferState                                frameBufferState(m_renderSize, m_renderSize);
280         frameBufferState.depthFormat    = depthFormat;
281         PipelineState                                   pipelineState(m_context.getDeviceProperties().limits.subPixelPrecisionBits);
282         DrawCallData                                    drawCallData(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, vertices);
283         VulkanDrawContext                               vulkanDrawContext(m_context, frameBufferState);
284
285         const std::vector<std::string>                          vertexShaderNames       = { "vertex1", "vertex2" };
286
287         log << tcu::TestLog::Message << "Testing position invariance." << tcu::TestLog::EndMessage;
288
289         for (deUint32 passNdx = 0; passNdx < 2; ++passNdx)
290         {
291                 std::vector<VulkanShader>                       shaders;
292                 shaders.push_back(VulkanShader(VK_SHADER_STAGE_VERTEX_BIT, m_context.getBinaryCollection().get(vertexShaderNames[passNdx])));
293                 shaders.push_back(VulkanShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("fragment")));
294                 VulkanProgram                                           vulkanProgram(shaders);
295                 vulkanProgram.descriptorSetLayout       = *descriptorSetLayout;
296                 vulkanProgram.descriptorSet                     = *descriptorSet[passNdx];
297
298                 const char* const                       colorStr = (passNdx == 0) ? ("red - purple") : ("green");
299                 log << tcu::TestLog::Message << "Drawing position test pattern using shader " << (passNdx + 1) << ". Primitive color: " << colorStr << "." << tcu::TestLog::EndMessage;
300
301                 vulkanDrawContext.registerDrawObject(pipelineState, vulkanProgram, drawCallData);
302         }
303         vulkanDrawContext.draw();
304
305         tcu::ConstPixelBufferAccess     resultImage(
306                 tcu::TextureFormat(vulkanDrawContext.getColorPixels().getFormat()),
307                 vulkanDrawContext.getColorPixels().getWidth(),
308                 vulkanDrawContext.getColorPixels().getHeight(),
309                 1,
310                 vulkanDrawContext.getColorPixels().getDataPtr());
311
312         log << tcu::TestLog::Message << "Verifying output. Expecting only green or background colored pixels." << tcu::TestLog::EndMessage;
313         if( !checkImage(resultImage) )
314                 return tcu::TestStatus::fail("Detected variance between two invariant values");
315
316         return tcu::TestStatus::pass("Passed");
317 }
318
319 bool InvarianceTestInstance::checkImage(const tcu::ConstPixelBufferAccess& image) const
320 {
321         const tcu::IVec4        okColor         (0, 255, 0, 255);
322         const tcu::RGBA         errColor        (255, 0, 0, 255);
323         bool                            error           = false;
324         tcu::Surface            errorMask       (image.getWidth(), image.getHeight());
325
326         tcu::clear(errorMask.getAccess(), okColor);
327
328         for (int y = 0; y < m_renderSize; ++y)
329                 for (int x = 0; x < m_renderSize; ++x)
330                 {
331                         const tcu::IVec4 col = image.getPixelInt(x, y);
332
333                         if (col.x() != 0)
334                         {
335                                 errorMask.setPixel(x, y, errColor);
336                                 error = true;
337                         }
338                 }
339
340         // report error
341         if (error)
342         {
343                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid pixels found (fragments from first render pass found). Variance detected." << tcu::TestLog::EndMessage;
344                 m_context.getTestContext().getLog()
345                         << tcu::TestLog::ImageSet("Results", "Result verification")
346                         << tcu::TestLog::Image("Result", "Result", image)
347                         << tcu::TestLog::Image("Error mask", "Error mask", errorMask)
348                         << tcu::TestLog::EndImageSet;
349
350                 return false;
351         }
352         else
353         {
354                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "No variance found." << tcu::TestLog::EndMessage;
355                 m_context.getTestContext().getLog()
356                         << tcu::TestLog::ImageSet("Results", "Result verification")
357                         << tcu::TestLog::Image("Result", "Result", image)
358                         << tcu::TestLog::EndImageSet;
359
360                 return true;
361         }
362 }
363
364 } // namespace
365
366 tcu::TestCaseGroup* createShaderInvarianceTests (tcu::TestContext& testCtx)
367 {
368         de::MovePtr<tcu::TestCaseGroup> invarianceGroup(new tcu::TestCaseGroup(testCtx, "invariance", "Invariance tests"));
369
370         static const struct PrecisionCase
371         {
372                 glu::Precision  prec;
373                 const char*             name;
374
375                 // set literals in the glsl to be in the representable range
376                 const char*             highValue;              // !< highValue < maxValue
377                 const char*             invHighValue;
378                 const char*             mediumValue;    // !< mediumValue^2 < maxValue
379                 const char*             lowValue;               // !< lowValue^4 < maxValue
380                 const char*             invlowValue;
381                 int                             loopIterations;
382                 int                             loopPartialIterations;
383                 int                             loopNormalizationExponent;
384                 const char*             loopNormalizationConstantLiteral;
385                 const char*             loopMultiplier;
386                 const char*             sumLoopNormalizationConstantLiteral;
387         } precisions[] =
388         {
389                 { 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" },
390                 { 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" },
391                 { glu::PRECISION_LOWP,          "lowp",         "0.9",          "1.1",          "1.1",          "1.15",         "0.87",         6,      2,      0,      "2.0",          "1.1",  "1.0"   },
392         };
393
394         // gl_Position must always be invariant for comparisons on gl_Position to be valid.
395         static const std::string invariantDeclaration[] = { "invariant gl_Position;", "invariant gl_Position;\nlayout(location = 1) invariant highp out vec4 v_value;" };
396         static const std::string invariantAssignment0[] = { "gl_Position", "v_value" };
397         static const std::string invariantAssignment1[] = { "", "gl_Position = v_value;" };
398         static const std::string fragDeclaration[]              = { "", "layout(location = 1) highp in vec4 v_value;" };
399
400         static const char* basicFragmentShader = "${VERSION}"
401                 "precision mediump float;\n"
402                 "${IN} vec4 v_unrelated;\n"
403                 "${FRAG_DECLARATION}\n"
404                 "layout(binding = 0) uniform ColorUniform\n"
405                 "{\n"
406                 "       vec4 u_color;\n"
407                 "} ucolor;\n"
408                 "layout(location = 0) out vec4 fragColor;\n"
409                 "void main ()\n"
410                 "{\n"
411                 "       float blue = dot(v_unrelated, vec4(1.0, 1.0, 1.0, 1.0));\n"
412                 "       fragColor = vec4(ucolor.u_color.r, ucolor.u_color.g, blue, ucolor.u_color.a);\n"
413                 "}\n";
414
415         for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); ++precNdx)
416         {
417                 const char* const                       precisionName = precisions[precNdx].name;
418                 const glu::Precision            precision = precisions[precNdx].prec;
419                 tcu::TestCaseGroup* const       group = new tcu::TestCaseGroup(testCtx, precisionName, "Invariance tests using the given precision.");
420
421                 const deUint32 VAR_GROUP_SIZE = 2u;
422                 tcu::TestCaseGroup* varGroup[VAR_GROUP_SIZE];
423                 varGroup[0] = new tcu::TestCaseGroup(testCtx, "gl_position", "Invariance tests using gl_Position variable");
424                 varGroup[1] = new tcu::TestCaseGroup(testCtx, "user_defined", "Invariance tests using user defined variable");
425                 FormatArgumentList      args[VAR_GROUP_SIZE];
426                 for (deUint32 groupNdx = 0u; groupNdx < VAR_GROUP_SIZE; ++groupNdx)
427                 {
428                         group->addChild(varGroup[groupNdx]);
429                         args[groupNdx] = FormatArgumentList()
430                                 << FormatArgument("VERSION",                            "#version 450\n")
431                                 << FormatArgument("IN",                                         "layout(location = 0) in")
432                                 << FormatArgument("OUT",                                        "layout(location = 0) out")
433                                 << FormatArgument("IN_PREC",                            precisionName)
434                                 << FormatArgument("INVARIANT_DECLARATION",      invariantDeclaration[groupNdx])
435                                 << FormatArgument("INVARIANT_ASSIGN_0",         invariantAssignment0[groupNdx])
436                                 << FormatArgument("INVARIANT_ASSIGN_1",         invariantAssignment1[groupNdx])
437                                 << FormatArgument("FRAG_DECLARATION",           fragDeclaration[groupNdx])
438                                 << FormatArgument("HIGH_VALUE",                         de::toString(precisions[precNdx].highValue))
439                                 << FormatArgument("HIGH_VALUE_INV",                     de::toString(precisions[precNdx].invHighValue))
440                                 << FormatArgument("MEDIUM_VALUE",                       de::toString(precisions[precNdx].mediumValue))
441                                 << FormatArgument("LOW_VALUE",                          de::toString(precisions[precNdx].lowValue))
442                                 << FormatArgument("LOW_VALUE_INV",                      de::toString(precisions[precNdx].invlowValue))
443                                 << FormatArgument("LOOP_ITERS",                         de::toString(precisions[precNdx].loopIterations))
444                                 << FormatArgument("LOOP_ITERS_PARTIAL",         de::toString(precisions[precNdx].loopPartialIterations))
445                                 << FormatArgument("LOOP_NORM_FRACT_EXP",        de::toString(precisions[precNdx].loopNormalizationExponent))
446                                 << FormatArgument("LOOP_NORM_LITERAL",          precisions[precNdx].loopNormalizationConstantLiteral)
447                                 << FormatArgument("LOOP_MULTIPLIER",            precisions[precNdx].loopMultiplier)
448                                 << FormatArgument("SUM_LOOP_NORM_LITERAL",      precisions[precNdx].sumLoopNormalizationConstantLiteral);
449                 }
450
451                 // subexpression cases
452                 for (deUint32 groupNdx = 0u; groupNdx < VAR_GROUP_SIZE; ++groupNdx)
453                 {
454                         // 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
455                         // due to the high exponent. In the second shader, the high exponent may be removed during compilation.
456
457                         varGroup[groupNdx]->addChild(new InvarianceTest(testCtx, "common_subexpression_0", "Shader shares a subexpression with an unrelated variable.",
458                                 formatGLSL("${VERSION}"
459                                         "${IN} ${IN_PREC} vec4 a_input;\n"
460                                         "${OUT} mediump vec4 v_unrelated;\n"
461                                         "${INVARIANT_DECLARATION}\n"
462                                         "void main ()\n"
463                                         "{\n"
464                                         "       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"
465                                         "       ${INVARIANT_ASSIGN_0} = a_input + (${HIGH_VALUE}*a_input.x*a_input.xxxx + ${HIGH_VALUE}*a_input.y*a_input.yyyy) * ${HIGH_VALUE_INV};\n"
466                                         "       ${INVARIANT_ASSIGN_1}\n"
467                                         "}\n", args[groupNdx]),
468                                 formatGLSL("${VERSION}"
469                                         "${IN} ${IN_PREC} vec4 a_input;\n"
470                                         "${OUT} mediump vec4 v_unrelated;\n"
471                                         "${INVARIANT_DECLARATION}\n"
472                                         "void main ()\n"
473                                         "{\n"
474                                         "       v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
475                                         "       ${INVARIANT_ASSIGN_0} = a_input + (${HIGH_VALUE}*a_input.x*a_input.xxxx + ${HIGH_VALUE}*a_input.y*a_input.yyyy) * ${HIGH_VALUE_INV};\n"
476                                         "       ${INVARIANT_ASSIGN_1}\n"
477                                         "}\n", args[groupNdx]),
478                                 formatGLSL(basicFragmentShader, args[groupNdx])));
479
480                         // In the first shader, the unrelated variable "d" has mathematically the same expression as "e", but the different
481                         // order of calculation might cause different results.
482
483                         varGroup[groupNdx]->addChild(new InvarianceTest(testCtx, "common_subexpression_1", "Shader shares a subexpression with an unrelated variable.",
484                                 formatGLSL("${VERSION}"
485                                         "${IN} ${IN_PREC} vec4 a_input;\n"
486                                         "${OUT} mediump vec4 v_unrelated;\n"
487                                         "${INVARIANT_DECLARATION}\n"
488                                         "void main ()\n"
489                                         "{\n"
490                                         "       ${IN_PREC} vec4 a = ${HIGH_VALUE} * a_input.zzxx + a_input.xzxy - ${HIGH_VALUE} * a_input.zzxx;\n"
491                                         "       ${IN_PREC} vec4 b = ${HIGH_VALUE} * a_input.zzxx;\n"
492                                         "       ${IN_PREC} vec4 c = b - ${HIGH_VALUE} * a_input.zzxx + a_input.xzxy;\n"
493                                         "       ${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"
494                                         "       ${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"
495                                         "       v_unrelated = a + b + c + d + e;\n"
496                                         "       ${INVARIANT_ASSIGN_0} = a_input + fract(c) + e;\n"
497                                         "       ${INVARIANT_ASSIGN_1}\n"
498                                         "}\n", args[groupNdx]),
499                                 formatGLSL("${VERSION}"
500                                         "${IN} ${IN_PREC} vec4 a_input;\n"
501                                         "${OUT} mediump vec4 v_unrelated;\n"
502                                         "${INVARIANT_DECLARATION}\n"
503                                         "void main ()\n"
504                                         "{\n"
505                                         "       ${IN_PREC} vec4 b = ${HIGH_VALUE} * a_input.zzxx;\n"
506                                         "       ${IN_PREC} vec4 c = b - ${HIGH_VALUE} * a_input.zzxx + a_input.xzxy;\n"
507                                         "       ${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"
508                                         "       v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
509                                         "       ${INVARIANT_ASSIGN_0} = a_input + fract(c) + e;\n"
510                                         "       ${INVARIANT_ASSIGN_1}\n"
511                                         "}\n", args[groupNdx]),
512                                 formatGLSL(basicFragmentShader, args[groupNdx])));
513
514                         // Intermediate values used by an unrelated output variable
515
516                         varGroup[groupNdx]->addChild(new InvarianceTest(testCtx, "common_subexpression_2", "Shader shares a subexpression with an unrelated variable.",
517                                 formatGLSL("${VERSION}"
518                                         "${IN} ${IN_PREC} vec4 a_input;\n"
519                                         "${OUT} mediump vec4 v_unrelated;\n"
520                                         "${INVARIANT_DECLARATION}\n"
521                                         "void main ()\n"
522                                         "{\n"
523                                         "       ${IN_PREC} vec4 a = ${MEDIUM_VALUE} * (a_input.xxxx + a_input.yyyy);\n"
524                                         "       ${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"
525                                         "       ${IN_PREC} vec4 c = a * a;\n"
526                                         "       ${IN_PREC} vec4 d = c / ${MEDIUM_VALUE} / ${MEDIUM_VALUE};\n"
527                                         "       v_unrelated = a + b + c + d;\n"
528                                         "       ${INVARIANT_ASSIGN_0} = a_input + d;\n"
529                                         "       ${INVARIANT_ASSIGN_1}\n"
530                                         "}\n", args[groupNdx]),
531                                 formatGLSL("${VERSION}"
532                                         "${IN} ${IN_PREC} vec4 a_input;\n"
533                                         "${OUT} mediump vec4 v_unrelated;\n"
534                                         "${INVARIANT_DECLARATION}\n"
535                                         "void main ()\n"
536                                         "{\n"
537                                         "       ${IN_PREC} vec4 a = ${MEDIUM_VALUE} * (a_input.xxxx + a_input.yyyy);\n"
538                                         "       ${IN_PREC} vec4 c = a * a;\n"
539                                         "       ${IN_PREC} vec4 d = c / ${MEDIUM_VALUE} / ${MEDIUM_VALUE};\n"
540                                         "       v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
541                                         "       ${INVARIANT_ASSIGN_0} = a_input + d;\n"
542                                         "       ${INVARIANT_ASSIGN_1}\n"
543                                         "}\n", args[groupNdx]),
544                                 formatGLSL(basicFragmentShader, args[groupNdx])));
545
546                         // Invariant value can be calculated using unrelated value
547
548                         varGroup[groupNdx]->addChild(new InvarianceTest(testCtx, "common_subexpression_3", "Shader shares a subexpression with an unrelated variable.",
549                                 formatGLSL("${VERSION}"
550                                         "${IN} ${IN_PREC} vec4 a_input;\n"
551                                         "${OUT} mediump vec4 v_unrelated;\n"
552                                         "${INVARIANT_DECLARATION}\n"
553                                         "void main ()\n"
554                                         "{\n"
555                                         "       ${IN_PREC} float x = a_input.x * 0.2;\n"
556                                         "       ${IN_PREC} vec4 a = a_input.xxyx * 0.7;\n"
557                                         "       ${IN_PREC} vec4 b = a_input.yxyz * 0.7;\n"
558                                         "       ${IN_PREC} vec4 c = a_input.zxyx * 0.5;\n"
559                                         "       ${IN_PREC} vec4 f = x*a + x*b + x*c;\n"
560                                         "       v_unrelated = f;\n"
561                                         "       ${IN_PREC} vec4 g = x * (a + b + c);\n"
562                                         "       ${INVARIANT_ASSIGN_0} = a_input + g;\n"
563                                         "       ${INVARIANT_ASSIGN_1}\n"
564                                         "}\n", args[groupNdx]),
565                                 formatGLSL("${VERSION}"
566                                         "${IN} ${IN_PREC} vec4 a_input;\n"
567                                         "${OUT} mediump vec4 v_unrelated;\n"
568                                         "${INVARIANT_DECLARATION}\n"
569                                         "void main ()\n"
570                                         "{\n"
571                                         "       ${IN_PREC} float x = a_input.x * 0.2;\n"
572                                         "       ${IN_PREC} vec4 a = a_input.xxyx * 0.7;\n"
573                                         "       ${IN_PREC} vec4 b = a_input.yxyz * 0.7;\n"
574                                         "       ${IN_PREC} vec4 c = a_input.zxyx * 0.5;\n"
575                                         "       v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
576                                         "       ${IN_PREC} vec4 g = x * (a + b + c);\n"
577                                         "       ${INVARIANT_ASSIGN_0} = a_input + g;\n"
578                                         "       ${INVARIANT_ASSIGN_1}\n"
579                                         "}\n", args[groupNdx]),
580                                 formatGLSL(basicFragmentShader, args[groupNdx])));
581                 }
582
583                 // shared subexpression of different precision
584                 for (deUint32 groupNdx = 0u; groupNdx < VAR_GROUP_SIZE; ++groupNdx)
585                 {
586                         for (int precisionOther = glu::PRECISION_LOWP; precisionOther != glu::PRECISION_LAST; ++precisionOther)
587                         {
588                                 const char* const               unrelatedPrec = glu::getPrecisionName((glu::Precision)precisionOther);
589                                 const glu::Precision    minPrecision = (precisionOther < (int)precision) ? ((glu::Precision)precisionOther) : (precision);
590                                 const char* const               multiplierStr = (minPrecision == glu::PRECISION_LOWP) ? ("0.8, 0.4, -0.2, 0.3") : ("1.0e1, 5.0e2, 2.0e2, 1.0");
591                                 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)");
592                                 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)");
593
594                                 varGroup[groupNdx]->addChild(new InvarianceTest(testCtx, ("subexpression_precision_" + std::string(unrelatedPrec)).c_str(), "Shader shares subexpression of different precision with an unrelated variable.",
595                                         formatGLSL("${VERSION}"
596                                                 "${IN} ${IN_PREC} vec4 a_input;\n"
597                                                 "${OUT} ${UNRELATED_PREC} vec4 v_unrelated;\n"
598                                                 "${INVARIANT_DECLARATION}\n"
599                                                 "void main ()\n"
600                                                 "{\n"
601                                                 "       ${UNRELATED_PREC} vec4 unrelated0 = a_input + vec4(0.1, 0.2, 0.3, 0.4);\n"
602                                                 "       ${UNRELATED_PREC} vec4 unrelated1 = vec4(${MULTIPLIER}) * unrelated0.xywz + unrelated0;\n"
603                                                 "       ${UNRELATED_PREC} vec4 unrelated2 = refract(unrelated1, unrelated0, distance(unrelated0, unrelated1));\n"
604                                                 "       v_unrelated = a_input + 0.02 * ${NORMALIZE_UNRELATED};\n"
605                                                 "       ${IN_PREC} vec4 used0 = a_input + vec4(0.1, 0.2, 0.3, 0.4);\n"
606                                                 "       ${IN_PREC} vec4 used1 = vec4(${MULTIPLIER}) * used0.xywz + used0;\n"
607                                                 "       ${IN_PREC} vec4 used2 = refract(used1, used0, distance(used0, used1));\n"
608                                                 "       ${INVARIANT_ASSIGN_0} = a_input + 0.02 * ${NORMALIZE_USED};\n"
609                                                 "       ${INVARIANT_ASSIGN_1}\n"
610                                                 "}\n", FormatArgumentList(args[groupNdx])
611                                                 << FormatArgument("UNRELATED_PREC", unrelatedPrec)
612                                                 << FormatArgument("MULTIPLIER", multiplierStr)
613                                                 << FormatArgument("NORMALIZE_USED", normalizationStrUsed)
614                                                 << FormatArgument("NORMALIZE_UNRELATED", normalizationStrUnrelated)),
615                                         formatGLSL("${VERSION}"
616                                                 "${IN} ${IN_PREC} vec4 a_input;\n"
617                                                 "${OUT} ${UNRELATED_PREC} vec4 v_unrelated;\n"
618                                                 "${INVARIANT_DECLARATION}\n"
619                                                 "void main ()\n"
620                                                 "{\n"
621                                                 "       v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
622                                                 "       ${IN_PREC} vec4 used0 = a_input + vec4(0.1, 0.2, 0.3, 0.4);\n"
623                                                 "       ${IN_PREC} vec4 used1 = vec4(${MULTIPLIER}) * used0.xywz + used0;\n"
624                                                 "       ${IN_PREC} vec4 used2 = refract(used1, used0, distance(used0, used1));\n"
625                                                 "       ${INVARIANT_ASSIGN_0} = a_input + 0.02 * ${NORMALIZE_USED};\n"
626                                                 "       ${INVARIANT_ASSIGN_1}\n"
627                                                 "}\n", FormatArgumentList(args[groupNdx])
628                                                 << FormatArgument("UNRELATED_PREC", unrelatedPrec)
629                                                 << FormatArgument("MULTIPLIER", multiplierStr)
630                                                 << FormatArgument("NORMALIZE_USED", normalizationStrUsed)
631                                                 << FormatArgument("NORMALIZE_UNRELATED", normalizationStrUnrelated)),
632                                         formatGLSL("${VERSION}"
633                                                 "precision mediump float;\n"
634                                                 "${IN} ${UNRELATED_PREC} vec4 v_unrelated;\n"
635                                                 "${FRAG_DECLARATION}\n"
636                                                 "layout(binding = 0) uniform ColorUniform\n"
637                                                 "{\n"
638                                                 "       vec4 u_color;\n"
639                                                 "} ucolor;\n"
640                                                 "${OUT} vec4 fragColor;\n"
641                                                 "void main ()\n"
642                                                 "{\n"
643                                                 "       float blue = dot(v_unrelated, vec4(1.0, 1.0, 1.0, 1.0));\n"
644                                                 "       fragColor = vec4(ucolor.u_color.r, ucolor.u_color.g, blue, ucolor.u_color.a);\n"
645                                                 "}\n", FormatArgumentList(args[groupNdx])
646                                                 << FormatArgument("UNRELATED_PREC", unrelatedPrec)
647                                                 << FormatArgument("MULTIPLIER", multiplierStr)
648                                                 << FormatArgument("NORMALIZE_USED", normalizationStrUsed)
649                                                 << FormatArgument("NORMALIZE_UNRELATED", normalizationStrUnrelated))));
650                         }
651                 }
652
653                 // loops
654                 for (deUint32 groupNdx = 0u; groupNdx < VAR_GROUP_SIZE; ++groupNdx)
655                 {
656                         varGroup[groupNdx]->addChild(new InvarianceTest(testCtx, "loop_0", "Invariant value set using a loop",
657                                 formatGLSL("${VERSION}"
658                                         "${IN} ${IN_PREC} vec4 a_input;\n"
659                                         "${OUT} highp vec4 v_unrelated;\n"
660                                         "${INVARIANT_DECLARATION}\n"
661                                         "void main ()\n"
662                                         "{\n"
663                                         "       ${IN_PREC} vec4 value = a_input;\n"
664                                         "       v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
665                                         "       for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
666                                         "       {\n"
667                                         "               value *= ${LOOP_MULTIPLIER};\n"
668                                         "               v_unrelated += value;\n"
669                                         "       }\n"
670                                         "       ${INVARIANT_ASSIGN_0} = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
671                                         "       ${INVARIANT_ASSIGN_1}\n"
672                                         "}\n", args[groupNdx]),
673                                 formatGLSL("${VERSION}"
674                                         "${IN} ${IN_PREC} vec4 a_input;\n"
675                                         "${OUT} highp vec4 v_unrelated;\n"
676                                         "${INVARIANT_DECLARATION}\n"
677                                         "void main ()\n"
678                                         "{\n"
679                                         "       ${IN_PREC} vec4 value = a_input;\n"
680                                         "       v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
681                                         "       for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
682                                         "       {\n"
683                                         "               value *= ${LOOP_MULTIPLIER};\n"
684                                         "       }\n"
685                                         "       ${INVARIANT_ASSIGN_0} = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
686                                         "       ${INVARIANT_ASSIGN_1}\n"
687                                         "}\n", args[groupNdx]),
688                                 formatGLSL("${VERSION}"
689                                         "precision mediump float;\n"
690                                         "layout(location=0) in highp vec4 v_unrelated;\n"
691                                         "${FRAG_DECLARATION}\n"
692                                         "layout(binding = 0) uniform ColorUniform\n"
693                                         "{\n"
694                                         "       vec4 u_color;\n"
695                                         "} ucolor;\n"
696                                         "layout(location = 0) out vec4 fragColor;\n"
697                                         "void main ()\n"
698                                         "{\n"
699                                         "       float blue = dot(v_unrelated, vec4(1.0, 1.0, 1.0, 1.0));\n"
700                                         "       fragColor = vec4(ucolor.u_color.r, ucolor.u_color.g, blue, ucolor.u_color.a);\n"
701                                         "}\n", args[groupNdx])));
702
703                         varGroup[groupNdx]->addChild(new InvarianceTest(testCtx, "loop_1", "Invariant value set using a loop",
704                                 formatGLSL("${VERSION}"
705                                         "${IN} ${IN_PREC} vec4 a_input;\n"
706                                         "${OUT} mediump vec4 v_unrelated;\n"
707                                         "${INVARIANT_DECLARATION}\n"
708                                         "void main ()\n"
709                                         "{\n"
710                                         "       ${IN_PREC} vec4 value = a_input;\n"
711                                         "       for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
712                                         "       {\n"
713                                         "               value *= ${LOOP_MULTIPLIER};\n"
714                                         "               if (i == ${LOOP_ITERS_PARTIAL})\n"
715                                         "                       v_unrelated = value;\n"
716                                         "       }\n"
717                                         "       ${INVARIANT_ASSIGN_0} = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
718                                         "       ${INVARIANT_ASSIGN_1}\n"
719                                         "}\n", args[groupNdx]),
720                                 formatGLSL("${VERSION}"
721                                         "${IN} ${IN_PREC} vec4 a_input;\n"
722                                         "${OUT} mediump vec4 v_unrelated;\n"
723                                         "${INVARIANT_DECLARATION}\n"
724                                         "void main ()\n"
725                                         "{\n"
726                                         "       ${IN_PREC} vec4 value = a_input;\n"
727                                         "       v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
728                                         "       for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
729                                         "       {\n"
730                                         "               value *= ${LOOP_MULTIPLIER};\n"
731                                         "       }\n"
732                                         "       ${INVARIANT_ASSIGN_0} = vec4(value.xyz / ${LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
733                                         "       ${INVARIANT_ASSIGN_1}\n"
734                                         "}\n", args[groupNdx]),
735                                 formatGLSL(basicFragmentShader, args[groupNdx])));
736
737                         varGroup[groupNdx]->addChild(new InvarianceTest(testCtx, "loop_2", "Invariant value set using a loop",
738                                 formatGLSL("${VERSION}"
739                                         "${IN} ${IN_PREC} vec4 a_input;\n"
740                                         "${OUT} mediump vec4 v_unrelated;\n"
741                                         "${INVARIANT_DECLARATION}\n"
742                                         "void main ()\n"
743                                         "{\n"
744                                         "       ${IN_PREC} vec4 value = a_input;\n"
745                                         "       v_unrelated = vec4(0.0, 0.0, -1.0, 1.0);\n"
746                                         "       for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
747                                         "       {\n"
748                                         "               value *= ${LOOP_MULTIPLIER};\n"
749                                         "               if (i == ${LOOP_ITERS_PARTIAL})\n"
750                                         "                       ${INVARIANT_ASSIGN_0} = a_input + 0.05 * vec4(fract(value.xyz / 1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n"
751                                         "               else\n"
752                                         "                       v_unrelated = value + a_input;\n"
753                                         "       ${INVARIANT_ASSIGN_1}\n"
754                                         "       }\n"
755                                         "}\n", args[groupNdx]),
756                                 formatGLSL("${VERSION}"
757                                         "${IN} ${IN_PREC} vec4 a_input;\n"
758                                         "${OUT} mediump vec4 v_unrelated;\n"
759                                         "${INVARIANT_DECLARATION}\n"
760                                         "void main ()\n"
761                                         "{\n"
762                                         "       ${IN_PREC} vec4 value = a_input;\n"
763                                         "       v_unrelated = vec4(0.0, 0.0, -1.0, 1.0);\n"
764                                         "       for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
765                                         "       {\n"
766                                         "               value *= ${LOOP_MULTIPLIER};\n"
767                                         "               if (i == ${LOOP_ITERS_PARTIAL})\n"
768                                         "                       ${INVARIANT_ASSIGN_0} = a_input + 0.05 * vec4(fract(value.xyz / 1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n"
769                                         "               else\n"
770                                         "                       v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
771                                         "       ${INVARIANT_ASSIGN_1}\n"
772                                         "       }\n"
773                                         "}\n", args[groupNdx]),
774                                 formatGLSL(basicFragmentShader, args[groupNdx])));
775
776                         varGroup[groupNdx]->addChild(new InvarianceTest(testCtx, "loop_3", "Invariant value set using a loop",
777                                 formatGLSL("${VERSION}"
778                                         "${IN} ${IN_PREC} vec4 a_input;\n"
779                                         "${OUT} mediump vec4 v_unrelated;\n"
780                                         "${INVARIANT_DECLARATION}\n"
781                                         "void main ()\n"
782                                         "{\n"
783                                         "       ${IN_PREC} vec4 value = a_input;\n"
784                                         "       ${INVARIANT_ASSIGN_0} = vec4(0.0, 0.0, 0.0, 0.0);\n"
785                                         "       v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
786                                         "       for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
787                                         "       {\n"
788                                         "               value *= ${LOOP_MULTIPLIER};\n"
789                                         "               ${INVARIANT_ASSIGN_0} += vec4(value.xyz / ${SUM_LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
790                                         "               v_unrelated = ${INVARIANT_ASSIGN_0}.xyzx * a_input;\n"
791                                         "       }\n"
792                                         "       ${INVARIANT_ASSIGN_1}\n"
793                                         "}\n", args[groupNdx]),
794                                 formatGLSL("${VERSION}"
795                                         "${IN} ${IN_PREC} vec4 a_input;\n"
796                                         "${OUT} mediump vec4 v_unrelated;\n"
797                                         "${INVARIANT_DECLARATION}\n"
798                                         "void main ()\n"
799                                         "{\n"
800                                         "       ${IN_PREC} vec4 value = a_input;\n"
801                                         "       ${INVARIANT_ASSIGN_0} = vec4(0.0, 0.0, 0.0, 0.0);\n"
802                                         "       v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
803                                         "       for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
804                                         "       {\n"
805                                         "               value *= ${LOOP_MULTIPLIER};\n"
806                                         "               ${INVARIANT_ASSIGN_0} += vec4(value.xyz / ${SUM_LOOP_NORM_LITERAL} + a_input.xyz * 0.1, 1.0);\n"
807                                         "       }\n"
808                                         "       ${INVARIANT_ASSIGN_1}\n"
809                                         "}\n", args[groupNdx]),
810                                 formatGLSL(basicFragmentShader, args[groupNdx])));
811
812                         varGroup[groupNdx]->addChild(new InvarianceTest(testCtx, "loop_4", "Invariant value set using a loop",
813                                 formatGLSL("${VERSION}"
814                                         "${IN} ${IN_PREC} vec4 a_input;\n"
815                                         "${OUT} mediump vec4 v_unrelated;\n"
816                                         "${INVARIANT_DECLARATION}\n"
817                                         "void main ()\n"
818                                         "{\n"
819                                         "       ${IN_PREC} vec4 position = vec4(0.0, 0.0, 0.0, 0.0);\n"
820                                         "       ${IN_PREC} vec4 value1 = a_input;\n"
821                                         "       ${IN_PREC} vec4 value2 = a_input;\n"
822                                         "       v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
823                                         "       for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
824                                         "       {\n"
825                                         "               value1 *= ${LOOP_MULTIPLIER};\n"
826                                         "               v_unrelated = v_unrelated*1.3 + a_input.xyzx * value1.xyxw;\n"
827                                         "       }\n"
828                                         "       for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
829                                         "       {\n"
830                                         "               value2 *= ${LOOP_MULTIPLIER};\n"
831                                         "               position = position*1.3 + a_input.xyzx * value2.xyxw;\n"
832                                         "       }\n"
833                                         "       ${INVARIANT_ASSIGN_0} = a_input + 0.05 * vec4(fract(position.xyz / 1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n"
834                                         "       ${INVARIANT_ASSIGN_1}\n"
835                                         "}\n", args[groupNdx]),
836                                 formatGLSL("${VERSION}"
837                                         "${IN} ${IN_PREC} vec4 a_input;\n"
838                                         "${OUT} mediump vec4 v_unrelated;\n"
839                                         "${INVARIANT_DECLARATION}\n"
840                                         "void main ()\n"
841                                         "{\n"
842                                         "       ${IN_PREC} vec4 position = vec4(0.0, 0.0, 0.0, 0.0);\n"
843                                         "       ${IN_PREC} vec4 value2 = a_input;\n"
844                                         "       v_unrelated = vec4(0.0, 0.0, 0.0, 0.0);\n"
845                                         "       for (mediump int i = 0; i < ${LOOP_ITERS}; ++i)\n"
846                                         "       {\n"
847                                         "               value2 *= ${LOOP_MULTIPLIER};\n"
848                                         "               position = position*1.3 + a_input.xyzx * value2.xyxw;\n"
849                                         "       }\n"
850                                         "       ${INVARIANT_ASSIGN_0} = a_input + 0.05 * vec4(fract(position.xyz / 1.0e${LOOP_NORM_FRACT_EXP}), 1.0);\n"
851                                         "       ${INVARIANT_ASSIGN_1}\n"
852                                         "}\n", args[groupNdx]),
853                                 formatGLSL(basicFragmentShader, args[groupNdx])));
854                 }
855                 invarianceGroup->addChild(group);
856         }
857         return invarianceGroup.release();
858 }
859
860 } // namespace sr
861
862 } // namespace vkt