Generate an error if no XFB varyings are in use

GLES specifies an error if BeginTransformFeedback is called when no
binding points would be used.

BUG=angleproject:2184
TEST=angle_end2end_tests

Change-Id: Ie4489b5ba63885e718dafdcdaacc02b603959be3
Reviewed-on: https://chromium-review.googlesource.com/719136
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/libANGLE/ErrorStrings.h b/src/libANGLE/ErrorStrings.h
index 9129f25..e056093 100644
--- a/src/libANGLE/ErrorStrings.h
+++ b/src/libANGLE/ErrorStrings.h
@@ -125,6 +125,8 @@
 ERRMSG(NegativeStart, "Cannot have negative start.");
 ERRMSG(NegativeStride, "Cannot have negative stride.");
 ERRMSG(NoSuchPath, "No such path object.");
+ERRMSG(NoTransformFeedbackOutputVariables,
+    "The active program has specified no output variables to record.");
 ERRMSG(NoZeroDivisor, "At least one enabled attribute must have a divisor of zero.");
 ERRMSG(ObjectNotGenerated, "Object cannot be used because it has not been generated.");
 ERRMSG(OffsetMustBeMultipleOfType, "Offset must be a multiple of the passed in datatype.");
diff --git a/src/libANGLE/validationES3.cpp b/src/libANGLE/validationES3.cpp
index 4f9c1e1..37a76d3 100644
--- a/src/libANGLE/validationES3.cpp
+++ b/src/libANGLE/validationES3.cpp
@@ -2139,6 +2139,20 @@
         }
     }
 
+    auto program = context->getGLState().getProgram();
+
+    if (!program)
+    {
+        ANGLE_VALIDATION_ERR(context, InvalidOperation(), ProgramNotBound);
+        return false;
+    }
+
+    if (program->getTransformFeedbackVaryingCount() == 0)
+    {
+        ANGLE_VALIDATION_ERR(context, InvalidOperation(), NoTransformFeedbackOutputVariables);
+        return false;
+    }
+
     return true;
 }
 
diff --git a/src/tests/gl_tests/TransformFeedbackTest.cpp b/src/tests/gl_tests/TransformFeedbackTest.cpp
index 47e17c6..dc7df16 100644
--- a/src/tests/gl_tests/TransformFeedbackTest.cpp
+++ b/src/tests/gl_tests/TransformFeedbackTest.cpp
@@ -1321,6 +1321,52 @@
     ASSERT_GL_NO_ERROR();
 }
 
+// Test that calling BeginTransformFeedback when no program is currentwill generate an
+// INVALID_OPERATION error.
+TEST_P(TransformFeedbackTest, NoCurrentProgram)
+{
+    glUseProgram(0);
+    glBeginTransformFeedback(GL_TRIANGLES);
+
+    // GLES 3.0.5 section 2.15.2: "The error INVALID_OPERATION is also generated by
+    // BeginTransformFeedback if no binding points would be used, either because no program object
+    // is active or because the active program object has specified no output variables to record."
+    EXPECT_GL_ERROR(GL_INVALID_OPERATION);
+}
+
+// Test that calling BeginTransformFeedback when no transform feedback varyings are in use will
+// generate an INVALID_OPERATION error.
+TEST_P(TransformFeedbackTest, NoTransformFeedbackVaryingsInUse)
+{
+    const std::string &vertexShaderSource =
+        "#version 300 es\n"
+        "in vec4 a_position;\n"
+        "void main()\n"
+        "{\n"
+        "    gl_Position = a_position;\n"
+        "}\n";
+
+    const std::string &fragmentShaderSource =
+        "#version 300 es\n"
+        "precision mediump float;\n"
+        "out vec4 fragColor;\n"
+        "void main()\n"
+        "{\n"
+        "    fragColor = vec4(0);\n"
+        "}\n";
+
+    ANGLE_GL_PROGRAM(program, vertexShaderSource, fragmentShaderSource);
+
+    glUseProgram(program);
+    glBeginTransformFeedback(GL_TRIANGLES);
+
+    // GLES 3.0.5 section 2.15.2: "The error INVALID_OPERATION is also generated by
+    // BeginTransformFeedback if no binding points would be used, either because no program object
+    // is active or because the active program object has specified no output variables to record."
+
+    EXPECT_GL_ERROR(GL_INVALID_OPERATION);
+}
+
 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
 // tests should be run against.
 ANGLE_INSTANTIATE_TEST(TransformFeedbackTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());