GLES2: sequence operator (,) eval order and side effects am: 073a0ffc99 am: 4755546e86
am: f0a4b07362

Change-Id: Ia68495c4716ec887b9ceebe222c404a02b1fac6a
diff --git a/android/cts/master/gles2-master.txt b/android/cts/master/gles2-master.txt
index b292fa5..0cf0fba 100644
--- a/android/cts/master/gles2-master.txt
+++ b/android/cts/master/gles2-master.txt
@@ -6033,6 +6033,9 @@
 dEQP-GLES2.functional.shaders.operator.sequence.side_effects.lowp_vec4_ivec4_bvec4_fragment
 dEQP-GLES2.functional.shaders.operator.sequence.side_effects.mediump_vec4_ivec4_bvec4_fragment
 dEQP-GLES2.functional.shaders.operator.sequence.side_effects.highp_vec4_ivec4_bvec4_fragment
+dEQP-GLES2.functional.shaders.operator.sequence.side_effects.affect_ternary
+dEQP-GLES2.functional.shaders.operator.sequence.side_effects.affect_and
+dEQP-GLES2.functional.shaders.operator.sequence.side_effects.affect_or
 dEQP-GLES2.functional.shaders.matrix.add.const_lowp_mat2_float_vertex
 dEQP-GLES2.functional.shaders.matrix.add.const_lowp_mat2_float_fragment
 dEQP-GLES2.functional.shaders.matrix.add.const_lowp_mat2_mat2_vertex
diff --git a/modules/gles2/functional/es2fShaderOperatorTests.cpp b/modules/gles2/functional/es2fShaderOperatorTests.cpp
index efe933c..46ef98d 100644
--- a/modules/gles2/functional/es2fShaderOperatorTests.cpp
+++ b/modules/gles2/functional/es2fShaderOperatorTests.cpp
@@ -1523,6 +1523,90 @@
 			}
 		}
 	}
+
+	// Regression tests for sequence operator.
+	// http://khronos.org/registry/webgl/sdk/tests/conformance/glsl/bugs/sequence-operator-evaluation-order.html
+	{
+		class Case : public ShaderRenderCase
+		{
+			static void evalFunc(ShaderEvalContext& c) {
+				c.color = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f); // green
+			}
+
+		public:
+			Case(Context& context, const char* name, const char* description, const char* fragShaderSource)
+				: ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, description, false, &evalFunc)
+			{
+				m_vertShaderSource =
+					"attribute vec4 a_position;\n"
+					"void main()\n"
+					"{\n"
+					"	gl_Position = a_position;\n"
+					"}\n";
+				m_fragShaderSource = fragShaderSource;
+			}
+		};
+
+		// ESSL 1.00 section 5.9, about sequence operator:
+		// "All expressions are evaluated, in order, from left to right"
+		// Also use a ternary operator where the third operand has side effects to make sure
+		// only the second operand is evaluated.
+		sequenceSideEffGroup->addChild(new Case(m_context, "affect_ternary",
+			"Expression where first operand of a sequence operator has side effects which affect the second operand that is a ternary operator", (
+				"precision mediump float;\n"
+				"bool correct = true;\n"
+				"uniform float u_zero;\n"
+				"float wrong() {\n"
+				"	correct = false;\n"
+				"	return 0.0;\n"
+				"}\n"
+				"void main() {\n"
+				"	float a = u_zero - 0.5; // Result should be -0.5.\n"
+				"	float green = (a++, a > 0.0 ? 1.0 : wrong());\n"
+				"	gl_FragColor = vec4(0.0, correct ? green : 0.0, 0.0, 1.0);\n"
+				"}\n"
+			)));
+
+		sequenceSideEffGroup->addChild(new Case(m_context, "affect_and",
+			"Expression where first operand of a sequence operator has side effects which affect the second operand that is an and operator", (
+				"precision mediump float;\n"
+				"uniform bool u_false;\n"
+				"bool sideEffectA = false;\n"
+				"bool funcA() {\n"
+				"	sideEffectA = true;\n"
+				"	return true;\n"
+				"}\n"
+				"bool sideEffectB = false;\n"
+				"bool funcB() {\n"
+				"	sideEffectB = true;\n"
+				"	return true;\n"
+				"}\n"
+				"void main() {\n"
+				"	bool b = (funcA(), u_false == sideEffectA && funcB());\n"
+				"	gl_FragColor = (!b && sideEffectA && !sideEffectB) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);\n"
+				"}\n"
+			)));
+
+		sequenceSideEffGroup->addChild(new Case(m_context, "affect_or",
+			"Expression where first operand of a sequence operator has side effects which affect the second operand that is an or operator", (
+				"precision mediump float;\n"
+				"uniform bool u_false;\n"
+				"bool sideEffectA = false;\n"
+				"bool funcA() {\n"
+				"	sideEffectA = true;\n"
+				"	return false;\n"
+				"}\n"
+				"bool sideEffectB = false;\n"
+				"bool funcB() {\n"
+				"	sideEffectB = true;\n"
+				"	return false;\n"
+				"}\n"
+				"void main() {\n"
+				"	bool b = (funcA(), (u_false == !sideEffectA) || funcB());\n"
+				"	gl_FragColor = (b && sideEffectA && !sideEffectB) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);\n"
+				"}\n"
+			)));
+	}
 }
 
 } // Functional