Home | History | Annotate | Download | only in functional
      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 
     51 static tcu::Vec4 genRandomVector (de::Random& rnd)
     52 {
     53 	tcu::Vec4 retVal;
     54 
     55 	retVal.x() = rnd.getFloat(-1.0f, 1.0f);
     56 	retVal.y() = rnd.getFloat(-1.0f, 1.0f);
     57 	retVal.z() = rnd.getFloat(-1.0f, 1.0f);
     58 	retVal.w() = rnd.getFloat( 0.2f, 1.0f);
     59 
     60 	return retVal;
     61 }
     62 
     63 class FormatArgument
     64 {
     65 public:
     66 						FormatArgument (const char* name, const std::string& value);
     67 
     68 private:
     69 	friend class FormatArgumentList;
     70 
     71 	const char* const	m_name;
     72 	const std::string	m_value;
     73 };
     74 
     75 FormatArgument::FormatArgument (const char* name, const std::string& value)
     76 	: m_name	(name)
     77 	, m_value	(value)
     78 {
     79 }
     80 
     81 class FormatArgumentList
     82 {
     83 public:
     84 												FormatArgumentList	(void);
     85 
     86 	FormatArgumentList&							operator<<			(const FormatArgument&);
     87 	const std::map<std::string, std::string>&	getArguments		(void) const;
     88 
     89 private:
     90 	std::map<std::string, std::string>			m_formatArguments;
     91 };
     92 
     93 FormatArgumentList::FormatArgumentList (void)
     94 {
     95 }
     96 
     97 FormatArgumentList&	FormatArgumentList::operator<< (const FormatArgument& arg)
     98 {
     99 	m_formatArguments[arg.m_name] = arg.m_value;
    100 	return *this;
    101 }
    102 
    103 const std::map<std::string, std::string>& FormatArgumentList::getArguments (void) const
    104 {
    105 	return m_formatArguments;
    106 }
    107 
    108 static std::string formatGLSL (const char* templateString, const FormatArgumentList& args)
    109 {
    110 	const std::map<std::string, std::string>& params = args.getArguments();
    111 
    112 	return tcu::StringTemplate(std::string(templateString)).specialize(params);
    113 }
    114 
    115 /*--------------------------------------------------------------------*//*!
    116  * \brief Vertex shader invariance test
    117  *
    118  * Test vertex shader invariance by drawing a test pattern two times, each
    119  * time with a different shader. Shaders have set identical values to
    120  * invariant gl_Position using identical expressions. No fragments from the
    121  * first pass using should remain visible.
    122  *//*--------------------------------------------------------------------*/
    123 class InvarianceTest : public TestCase
    124 {
    125 public:
    126 	struct ShaderPair
    127 	{
    128 		std::string vertexShaderSource0;
    129 		std::string fragmentShaderSource0;
    130 		std::string vertexShaderSource1;
    131 		std::string fragmentShaderSource1;
    132 	};
    133 
    134 							InvarianceTest		(Context& ctx, const char* name, const char* desc);
    135 							~InvarianceTest		(void);
    136 
    137 	void					init				(void);
    138 	void					deinit				(void);
    139 	IterateResult			iterate				(void);
    140 
    141 private:
    142 	virtual ShaderPair		genShaders			(void) const = DE_NULL;
    143 	bool					checkImage			(const tcu::Surface&) const;
    144 
    145 	glu::ShaderProgram*		m_shader0;
    146 	glu::ShaderProgram*		m_shader1;
    147 	glw::GLuint				m_arrayBuf;
    148 	int						m_verticesInPattern;
    149 
    150 	const int				m_renderSize;
    151 };
    152 
    153 InvarianceTest::InvarianceTest (Context& ctx, const char* name, const char* desc)
    154 	: TestCase				(ctx, name, desc)
    155 	, m_shader0				(DE_NULL)
    156 	, m_shader1				(DE_NULL)
    157 	, m_arrayBuf			(0)
    158 	, m_verticesInPattern	(0)
    159 	, m_renderSize			(256)
    160 {
    161 }
    162 
    163 InvarianceTest::~InvarianceTest (void)
    164 {
    165 	deinit();
    166 }
    167 
    168 void InvarianceTest::init (void)
    169 {
    170 	// Invariance tests require drawing to the screen and reading back results.
    171 	// Tests results are not reliable if the resolution is too small
    172 	{
    173 		if (m_context.getRenderTarget().getWidth()  < m_renderSize ||
    174 			m_context.getRenderTarget().getHeight() < m_renderSize)
    175 			throw tcu::NotSupportedError(std::string("Render target size must be at least ") + de::toString(m_renderSize) + "x" + de::toString(m_renderSize));
    176 	}
    177 
    178 	// Gen shaders
    179 	{
    180 		ShaderPair vertexShaders = genShaders();
    181 
    182 		m_shader0 = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexShaders.vertexShaderSource0) << glu::FragmentSource(vertexShaders.fragmentShaderSource0));
    183 		if (!m_shader0->isOk())
    184 		{
    185 			m_testCtx.getLog() << *m_shader0;
    186 			throw tcu::TestError("Test shader compile failed.");
    187 		}
    188 
    189 		m_shader1 = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexShaders.vertexShaderSource1) << glu::FragmentSource(vertexShaders.fragmentShaderSource1));
    190 		if (!m_shader1->isOk())
    191 		{
    192 			m_testCtx.getLog() << *m_shader1;
    193 			throw tcu::TestError("Test shader compile failed.");
    194 		}
    195 
    196 		// log
    197 		m_testCtx.getLog()
    198 			<< tcu::TestLog::Message << "Shader 1:" << tcu::TestLog::EndMessage
    199 			<< *m_shader0
    200 			<< tcu::TestLog::Message << "Shader 2:" << tcu::TestLog::EndMessage
    201 			<< *m_shader1;
    202 	}
    203 
    204 	// Gen test pattern
    205 	{
    206 		const int				numTriangles	= 72;
    207 		de::Random				rnd				(123);
    208 		std::vector<tcu::Vec4>	triangles		(numTriangles * 3 * 2);
    209 		const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
    210 
    211 		// Narrow triangle pattern
    212 		for (int triNdx = 0; triNdx < numTriangles; ++triNdx)
    213 		{
    214 			const tcu::Vec4 vertex1 = genRandomVector(rnd);
    215 			const tcu::Vec4 vertex2 = genRandomVector(rnd);
    216 			const tcu::Vec4 vertex3 = vertex2 + genRandomVector(rnd) * 0.01f; // generate narrow triangles
    217 
    218 			triangles[triNdx*3 + 0] = vertex1;
    219 			triangles[triNdx*3 + 1] = vertex2;
    220 			triangles[triNdx*3 + 2] = vertex3;
    221 		}
    222 
    223 		// Normal triangle pattern
    224 		for (int triNdx = 0; triNdx < numTriangles; ++triNdx)
    225 		{
    226 			triangles[(numTriangles + triNdx)*3 + 0] = genRandomVector(rnd);
    227 			triangles[(numTriangles + triNdx)*3 + 1] = genRandomVector(rnd);
    228 			triangles[(numTriangles + triNdx)*3 + 2] = genRandomVector(rnd);
    229 		}
    230 
    231 		// upload
    232 		gl.genBuffers(1, &m_arrayBuf);
    233 		gl.bindBuffer(GL_ARRAY_BUFFER, m_arrayBuf);
    234 		gl.bufferData(GL_ARRAY_BUFFER, (int)(triangles.size() * sizeof(tcu::Vec4)), &triangles[0], GL_STATIC_DRAW);
    235 		GLU_EXPECT_NO_ERROR(gl.getError(), "buffer gen");
    236 
    237 		m_verticesInPattern = numTriangles * 3;
    238 	}
    239 }
    240 
    241 void InvarianceTest::deinit (void)
    242 {
    243 	delete m_shader0;
    244 	delete m_shader1;
    245 
    246 	m_shader0 = DE_NULL;
    247 	m_shader1 = DE_NULL;
    248 
    249 	if (m_arrayBuf)
    250 	{
    251 		m_context.getRenderContext().getFunctions().deleteBuffers(1, &m_arrayBuf);
    252 		m_arrayBuf = 0;
    253 	}
    254 }
    255 
    256 InvarianceTest::IterateResult InvarianceTest::iterate (void)
    257 {
    258 	const glw::Functions&	gl					= m_context.getRenderContext().getFunctions();
    259 	const bool				depthBufferExists	= m_context.getRenderTarget().getDepthBits() != 0;
    260 	tcu::Surface			resultSurface		(m_renderSize, m_renderSize);
    261 	bool					error				= false;
    262 
    263 	// Prepare draw
    264 	gl.clearColor		(0.0f, 0.0f, 0.0f, 1.0f);
    265 	gl.clear			(GL_COLOR_BUFFER_BIT);
    266 	gl.viewport			(0, 0, m_renderSize, m_renderSize);
    267 	gl.bindBuffer		(GL_ARRAY_BUFFER, m_arrayBuf);
    268 	GLU_EXPECT_NO_ERROR	(gl.getError(), "setup draw");
    269 
    270 	m_testCtx.getLog() << tcu::TestLog::Message << "Testing position invariance." << tcu::TestLog::EndMessage;
    271 
    272 	// Draw position check passes
    273 	for (int passNdx = 0; passNdx < 2; ++passNdx)
    274 	{
    275 		const glu::ShaderProgram&	shader		= (passNdx == 0) ? (*m_shader0) : (*m_shader1);
    276 		const glw::GLint			positionLoc = gl.getAttribLocation(shader.getProgram(), "a_input");
    277 		const glw::GLint			colorLoc	= gl.getUniformLocation(shader.getProgram(), "u_color");
    278 		const tcu::Vec4				red			= tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
    279 		const tcu::Vec4				green		= tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
    280 		const tcu::Vec4				color		= (passNdx == 0) ? (red) : (green);
    281 		const char* const			colorStr	= (passNdx == 0) ? ("red - purple") : ("green");
    282 
    283 		m_testCtx.getLog() << tcu::TestLog::Message << "Drawing position test pattern using shader " << (passNdx+1) << ". Primitive color: " << colorStr << "." << tcu::TestLog::EndMessage;
    284 
    285 		gl.useProgram				(shader.getProgram());
    286 		gl.uniform4fv				(colorLoc, 1, color.getPtr());
    287 		gl.enableVertexAttribArray	(positionLoc);
    288 		gl.vertexAttribPointer		(positionLoc, 4, GL_FLOAT, GL_FALSE, sizeof(tcu::Vec4), DE_NULL);
    289 		gl.drawArrays				(GL_TRIANGLES, 0, m_verticesInPattern);
    290 		gl.disableVertexAttribArray	(positionLoc);
    291 		GLU_EXPECT_NO_ERROR			(gl.getError(), "draw pass");
    292 	}
    293 
    294 	// Read result
    295 	glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess());
    296 
    297 	// Check there are no red pixels
    298 	m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output. Expecting only green or background colored pixels." << tcu::TestLog::EndMessage;
    299 	error |= !checkImage(resultSurface);
    300 
    301 	if (!depthBufferExists)
    302 	{
    303 		m_testCtx.getLog() << tcu::TestLog::Message << "Depth buffer not available, skipping z-test." << tcu::TestLog::EndMessage;
    304 	}
    305 	else
    306 	{
    307 		// Test with Z-test
    308 		gl.clearDepthf		(1.0f);
    309 		gl.clear			(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    310 		gl.enable			(GL_DEPTH_TEST);
    311 
    312 		m_testCtx.getLog() << tcu::TestLog::Message << "Testing position invariance with z-test. Enabling GL_DEPTH_TEST." << tcu::TestLog::EndMessage;
    313 
    314 		// Draw position check passes
    315 		for (int passNdx = 0; passNdx < 2; ++passNdx)
    316 		{
    317 			const glu::ShaderProgram&	shader			= (passNdx == 0) ? (*m_shader0) : (*m_shader1);
    318 			const glw::GLint			positionLoc		= gl.getAttribLocation(shader.getProgram(), "a_input");
    319 			const glw::GLint			colorLoc		= gl.getUniformLocation(shader.getProgram(), "u_color");
    320 			const tcu::Vec4				red				= tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
    321 			const tcu::Vec4				green			= tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
    322 			const tcu::Vec4				color			= (passNdx == 0) ? (red) : (green);
    323 			const glw::GLenum			depthFunc		= (passNdx == 0) ? (GL_ALWAYS) : (GL_EQUAL);
    324 			const char* const			depthFuncStr	= (passNdx == 0) ? ("GL_ALWAYS") : ("GL_EQUAL");
    325 			const char* const			colorStr		= (passNdx == 0) ? ("red - purple") : ("green");
    326 
    327 			m_testCtx.getLog() << tcu::TestLog::Message << "Drawing Z-test pattern using shader " << (passNdx+1) << ". Primitive color: " << colorStr << ". DepthFunc: " << depthFuncStr << tcu::TestLog::EndMessage;
    328 
    329 			gl.useProgram				(shader.getProgram());
    330 			gl.uniform4fv				(colorLoc, 1, color.getPtr());
    331 			gl.depthFunc				(depthFunc);
    332 			gl.enableVertexAttribArray	(positionLoc);
    333 			gl.vertexAttribPointer		(positionLoc, 4, GL_FLOAT, GL_FALSE, sizeof(tcu::Vec4), DE_NULL);
    334 			gl.drawArrays				(GL_TRIANGLES, m_verticesInPattern, m_verticesInPattern); // !< buffer contains 2 m_verticesInPattern-sized patterns
    335 			gl.disableVertexAttribArray	(positionLoc);
    336 			GLU_EXPECT_NO_ERROR			(gl.getError(), "draw pass");
    337 		}
    338 
    339 		// Read result
    340 		glu::readPixels(m_context.getRenderContext(), 0, 0, resultSurface.getAccess());
    341 
    342 		// Check there are no red pixels
    343 		m_testCtx.getLog() << tcu::TestLog::Message << "Verifying output. Expecting only green or background colored pixels." << tcu::TestLog::EndMessage;
    344 		error |= !checkImage(resultSurface);
    345 	}
    346 
    347 	// Report result
    348 	if (error)
    349 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Detected variance between two invariant values");
    350 	else
    351 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    352 
    353 	return STOP;
    354 }
    355 
    356 bool InvarianceTest::checkImage (const tcu::Surface& surface) const
    357 {
    358 	const tcu::IVec4	okColor		= tcu::IVec4(0, 255, 0, 255);
    359 	const tcu::RGBA		errColor	= tcu::RGBA(255, 0, 0, 255);
    360 	bool				error		= false;
    361 	tcu::Surface		errorMask	(m_renderSize, m_renderSize);
    362 
    363 	tcu::clear(errorMask.getAccess(), okColor);
    364 
    365 	for (int y = 0; y < m_renderSize; ++y)
    366 	for (int x = 0; x < m_renderSize; ++x)
    367 	{
    368 		const tcu::RGBA col = surface.getPixel(x, y);
    369 
    370 		if (col.getRed() != 0)
    371 		{
    372 			errorMask.setPixel(x, y, errColor);
    373 			error = true;
    374 		}
    375 	}
    376 
    377 	// report error
    378 	if (error)
    379 	{
    380 		m_testCtx.getLog() << tcu::TestLog::Message << "Invalid pixels found (fragments from first render pass found). Variance detected." << tcu::TestLog::EndMessage;
    381 		m_testCtx.getLog()
    382 			<< tcu::TestLog::ImageSet("Results", "Result verification")
    383 			<< tcu::TestLog::Image("Result",		"Result",		surface)
    384 			<< tcu::TestLog::Image("Error mask",	"Error mask",	errorMask)
    385 			<< tcu::TestLog::EndImageSet;
    386 
    387 		return false;
    388 	}
    389 	else
    390 	{
    391 		m_testCtx.getLog() << tcu::TestLog::Message << "No variance found." << tcu::TestLog::EndMessage;
    392 		m_testCtx.getLog()
    393 			<< tcu::TestLog::ImageSet("Results", "Result verification")
    394 			<< tcu::TestLog::Image("Result", "Result", surface)
    395 			<< tcu::TestLog::EndImageSet;
    396 
    397 		return true;
    398 	}
    399 }
    400 
    401 class BasicInvarianceTest : public InvarianceTest
    402 {
    403 public:
    404 								BasicInvarianceTest		(Context& ctx, const char* name, const char* desc, const std::string& vertexShader1, const std::string& vertexShader2);
    405 								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 
    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 
    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 
    441 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 
    455 ShaderInvarianceTests::ShaderInvarianceTests (Context& context)
    456 	: TestCaseGroup(context, "invariance", "Invariance tests")
    457 {
    458 }
    459 
    460 ShaderInvarianceTests::~ShaderInvarianceTests (void)
    461 {
    462 }
    463 
    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