dEQP: Add command-line parsing of back-end.

Also use the requested renderer to initialize expectations.

BUG=angleproject:1442

Change-Id: Idf54072dac5f7ad9deea70e97d65e36a6e883b1c
Reviewed-on: https://chromium-review.googlesource.com/407802
Commit-Queue: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/tests/deqp_support/angle_deqp_gtest.cpp b/src/tests/deqp_support/angle_deqp_gtest.cpp
index f3dbb5c..89f3f8a 100644
--- a/src/tests/deqp_support/angle_deqp_gtest.cpp
+++ b/src/tests/deqp_support/angle_deqp_gtest.cpp
@@ -45,6 +45,50 @@
     "deqp_gles31_test_expectations.txt", "deqp_egl_test_expectations.txt",
 };
 
+using APIInfo = std::pair<const char *, gpu::GPUTestConfig::API>;
+
+const APIInfo g_eglDisplayAPIs[] = {
+    {"angle-d3d9", gpu::GPUTestConfig::kAPID3D9},
+    {"angle-d3d11", gpu::GPUTestConfig::kAPID3D11},
+    {"angle-gl", gpu::GPUTestConfig::kAPIGLDesktop},
+    {"angle-gles", gpu::GPUTestConfig::kAPIGLES},
+};
+
+const APIInfo *g_initAPI = nullptr;
+
+// Returns the default API for a platform.
+const char *GetDefaultAPIName()
+{
+#if defined(ANGLE_PLATFORM_WINDOWS)
+    return "angle-d3d11";
+#elif defined(ANGLE_PLATFORM_APPLE) || defined(ANGLE_PLATFORM_LINUX)
+    return "angle-gl";
+#elif defined(ANGLE_PLATFORM_ANDROID)
+    return "angle-gles";
+#else
+#error Unknown platform.
+#endif
+}
+
+const APIInfo *FindAPIInfo(const std::string &arg)
+{
+    for (auto &displayAPI : g_eglDisplayAPIs)
+    {
+        if (arg == displayAPI.first)
+        {
+            return &displayAPI;
+        }
+    }
+    return nullptr;
+}
+
+const APIInfo *GetDefaultAPIInfo()
+{
+    const APIInfo *defaultInfo = FindAPIInfo(GetDefaultAPIName());
+    ASSERT(defaultInfo);
+    return defaultInfo;
+}
+
 // During the CaseList initialization we cannot use the GTEST FAIL macro to quit the program because
 // the initialization is called outside of tests the first time.
 void Die()
@@ -162,6 +206,16 @@
         Die();
     }
 
+    // Set the API from the command line, or using the default platform API.
+    if (g_initAPI)
+    {
+        mTestConfig.set_api(g_initAPI->second);
+    }
+    else
+    {
+        mTestConfig.set_api(GetDefaultAPIInfo()->second);
+    }
+
     std::ifstream caseListStream(caseListPath);
     if (caseListStream.fail())
     {
@@ -215,13 +269,7 @@
         return sCaseList;
     }
 
-    static void SetUpTestCase()
-    {
-        sPasses           = 0;
-        sFails            = 0;
-        sUnexpectedPasses = 0;
-    }
-
+    static void SetUpTestCase();
     static void TearDownTestCase();
 
   protected:
@@ -263,6 +311,33 @@
 
 // static
 template <size_t TestModuleIndex>
+void dEQPTest<TestModuleIndex>::SetUpTestCase()
+{
+    sPasses           = 0;
+    sFails            = 0;
+    sUnexpectedPasses = 0;
+
+    int argc = 0;
+    std::vector<const char *> argv;
+
+    // Reserve one argument for the binary name.
+    argc++;
+    argv.push_back("");
+
+    // Add init api.
+    argc++;
+    argv.push_back(g_initAPI ? g_initAPI->first : GetDefaultAPIName());
+
+    // Init the platform.
+    if (!deqp_libtester_init_platform(argc, argv.data()))
+    {
+        std::cout << "Aborting test due to dEQP initialization error." << std::endl;
+        exit(1);
+    }
+}
+
+// static
+template <size_t TestModuleIndex>
 void dEQPTest<TestModuleIndex>::TearDownTestCase()
 {
     unsigned int total = sPasses + sFails;
@@ -279,9 +354,10 @@
     {
         std::cout << sUnexpectedPasses << " tests unexpectedly passed." << std::endl;
     }
+
+    deqp_libtester_shutdown_platform();
 }
 
-// TODO(jmadill): add different platform configs, or ability to choose platform
 #define ANGLE_INSTANTIATE_DEQP_TEST_CASE(DEQP_TEST, N)                          \
     class DEQP_TEST : public dEQPTest<N>                                        \
     {                                                                           \
@@ -309,4 +385,69 @@
 ANGLE_INSTANTIATE_DEQP_TEST_CASE(dEQP_EGL, 3);
 #endif
 
+const char *g_deqpEGLString  = "--deqp-egl-display-type=";
+const char *g_angleEGLString = "--use-angle=";
+
+void HandleDisplayType(const char *displayTypeString)
+{
+    std::stringstream argStream;
+
+    if (g_initAPI)
+    {
+        std::cout << "Cannot specify two EGL displays!" << std::endl;
+        exit(1);
+    }
+
+    if (strncmp(displayTypeString, "angle-", strlen("angle-")) != 0)
+    {
+        argStream << "angle-";
+    }
+
+    argStream << displayTypeString;
+    std::string arg = argStream.str();
+
+    g_initAPI = FindAPIInfo(arg);
+
+    if (!g_initAPI)
+    {
+        std::cout << "Unknown ANGLE back-end API: " << displayTypeString << std::endl;
+        exit(1);
+    }
+}
+
+void DeleteArg(int *argc, int argIndex, char **argv)
+{
+    (*argc)--;
+    for (int moveIndex = argIndex; moveIndex < *argc; ++moveIndex)
+    {
+        argv[moveIndex] = argv[moveIndex + 1];
+    }
+}
+
 } // anonymous namespace
+
+// Called from main() to process command-line arguments.
+namespace angle
+{
+void InitTestHarness(int *argc, char **argv)
+{
+    int argIndex = 0;
+    while (argIndex < *argc)
+    {
+        if (strncmp(argv[argIndex], g_deqpEGLString, strlen(g_deqpEGLString)) == 0)
+        {
+            HandleDisplayType(argv[argIndex] + strlen(g_deqpEGLString));
+            DeleteArg(argc, argIndex, argv);
+        }
+        else if (strncmp(argv[argIndex], g_angleEGLString, strlen(g_angleEGLString)) == 0)
+        {
+            HandleDisplayType(argv[argIndex] + strlen(g_angleEGLString));
+            DeleteArg(argc, argIndex, argv);
+        }
+        else
+        {
+            argIndex++;
+        }
+    }
+}
+}  // namespace angle
diff --git a/src/tests/deqp_support/angle_deqp_gtest_main.cpp b/src/tests/deqp_support/angle_deqp_gtest_main.cpp
index 154820a..e72417f 100644
--- a/src/tests/deqp_support/angle_deqp_gtest_main.cpp
+++ b/src/tests/deqp_support/angle_deqp_gtest_main.cpp
@@ -8,12 +8,17 @@
 
 #include <gtest/gtest.h>
 
-#include "angle_deqp_libtester.h"
+// Defined in angle_deqp_gtest.cpp. Declared here so we don't need to make a header that we import
+// in Chromium.
+namespace angle
+{
+void InitTestHarness(int *argc, char **argv);
+}  // namespace angle
 
 int main(int argc, char **argv)
 {
+    angle::InitTestHarness(&argc, argv);
     testing::InitGoogleTest(&argc, argv);
     int rt = RUN_ALL_TESTS();
-    deqp_libtester_shutdown_platform();
     return rt;
 }
diff --git a/src/tests/deqp_support/angle_deqp_libtester.h b/src/tests/deqp_support/angle_deqp_libtester.h
index 3e60f74..7f35ddb 100644
--- a/src/tests/deqp_support/angle_deqp_libtester.h
+++ b/src/tests/deqp_support/angle_deqp_libtester.h
@@ -28,6 +28,7 @@
 
 // Exported to the tester app.
 ANGLE_LIBTESTER_EXPORT int deqp_libtester_main(int argc, const char *argv[]);
+ANGLE_LIBTESTER_EXPORT bool deqp_libtester_init_platform(int argc, const char *argv[]);
 ANGLE_LIBTESTER_EXPORT void deqp_libtester_shutdown_platform();
 ANGLE_LIBTESTER_EXPORT bool deqp_libtester_run(const char *caseName);
 
diff --git a/src/tests/deqp_support/angle_deqp_libtester_main.cpp b/src/tests/deqp_support/angle_deqp_libtester_main.cpp
index 1eb24a9..90727f3 100644
--- a/src/tests/deqp_support/angle_deqp_libtester_main.cpp
+++ b/src/tests/deqp_support/angle_deqp_libtester_main.cpp
@@ -117,7 +117,9 @@
 #endif
 }
 
-bool InitPlatform(int argc, const char *argv[])
+}  // anonymous namespace
+
+ANGLE_LIBTESTER_EXPORT bool deqp_libtester_init_platform(int argc, const char *argv[])
 {
     try
     {
@@ -156,12 +158,10 @@
     return true;
 }
 
-} // anonymous namespace
-
 // Exported to the tester app.
 ANGLE_LIBTESTER_EXPORT int deqp_libtester_main(int argc, const char *argv[])
 {
-    if (!InitPlatform(argc, argv))
+    if (!deqp_libtester_init_platform(argc, argv))
     {
         tcu::die("Could not initialize the dEQP platform");
     }
@@ -190,18 +190,25 @@
 ANGLE_LIBTESTER_EXPORT void deqp_libtester_shutdown_platform()
 {
     delete g_executor;
+    g_executor = nullptr;
     delete g_root;
+    g_root = nullptr;
     delete g_testCtx;
+    g_testCtx = nullptr;
     delete g_log;
+    g_log = nullptr;
     delete g_archive;
+    g_archive = nullptr;
     delete g_cmdLine;
+    g_cmdLine = nullptr;
     delete g_platform;
+    g_platform = nullptr;
 }
 
 ANGLE_LIBTESTER_EXPORT bool deqp_libtester_run(const char *caseName)
 {
     const char *emptyString = "";
-    if (g_platform == nullptr && !InitPlatform(1, &emptyString))
+    if (g_platform == nullptr && !deqp_libtester_init_platform(1, &emptyString))
     {
         tcu::die("Failed to initialize platform.");
     }