• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // angle_deqp_gtest:
7 //   dEQP and GoogleTest integration logic. Calls through to the random
8 //   order executor.
9 
10 #include <stdint.h>
11 #include <array>
12 #include <fstream>
13 
14 #include <gtest/gtest.h>
15 
16 #include "angle_deqp_libtester.h"
17 #include "common/Optional.h"
18 #include "common/angleutils.h"
19 #include "common/base/anglebase/no_destructor.h"
20 #include "common/debug.h"
21 #include "common/platform.h"
22 #include "common/string_utils.h"
23 #include "common/system_utils.h"
24 #include "platform/PlatformMethods.h"
25 #include "tests/test_utils/runner/TestSuite.h"
26 #include "util/OSWindow.h"
27 #include "util/test_utils.h"
28 
29 namespace angle
30 {
31 namespace
32 {
33 #if !defined(NDEBUG)
34 constexpr bool kIsDebug = true;
35 #else
36 constexpr bool kIsDebug = false;
37 #endif  // !defined(NDEBUG)
38 
39 bool gGlobalError = false;
40 bool gExpectError = false;
41 bool gVerbose     = false;
42 
43 // Set this to true temporarily to enable image logging in release. Useful for diagnosing
44 // errors.
45 bool gLogImages = kIsDebug;
46 
47 constexpr char kInfoTag[] = "*RESULT";
48 
HandlePlatformError(PlatformMethods * platform,const char * errorMessage)49 void HandlePlatformError(PlatformMethods *platform, const char *errorMessage)
50 {
51     if (!gExpectError)
52     {
53         FAIL() << errorMessage;
54     }
55     gGlobalError = true;
56 }
57 
58 // Relative to the ANGLE root folder.
59 constexpr char kCTSRootPath[] = "third_party/VK-GL-CTS/src/";
60 constexpr char kSupportPath[] = "src/tests/deqp_support/";
61 
62 #define GLES_CTS_DIR(PATH) "external/openglcts/data/gl_cts/data/mustpass/gles/" PATH
63 #define GL_CTS_DIR(PATH) "external/openglcts/data/gl_cts/data/mustpass/gl/" PATH
64 #define EGL_CTS_DIR(PATH) "external/openglcts/data/gl_cts/data/mustpass/egl/" PATH
65 
66 const char *gCaseListFiles[] = {
67     EGL_CTS_DIR("aosp_mustpass/main/egl-main.txt"),
68     GLES_CTS_DIR("aosp_mustpass/main/gles2-main.txt"),
69     GLES_CTS_DIR("aosp_mustpass/main/gles3-main.txt"),
70     GLES_CTS_DIR("aosp_mustpass/main/gles31-main.txt"),
71     GLES_CTS_DIR("khronos_mustpass/main/gles2-khr-main.txt"),
72     GLES_CTS_DIR("khronos_mustpass/main/gles3-khr-main.txt"),
73     GLES_CTS_DIR("khronos_mustpass/main/gles31-khr-main.txt"),
74     GLES_CTS_DIR("khronos_mustpass/main/gles32-khr-main.txt"),
75     GLES_CTS_DIR("khronos_mustpass_noctx/main/gles2-khr-noctx-main.txt"),
76     GLES_CTS_DIR("khronos_mustpass_noctx/main/gles32-khr-noctx-main.txt"),
77     GLES_CTS_DIR("khronos_mustpass_single/main/gles32-khr-single.txt"),
78     GLES_CTS_DIR("aosp_mustpass/main/gles3-rotate-landscape.txt"),
79     GLES_CTS_DIR("aosp_mustpass/main/gles3-rotate-reverse-portrait.txt"),
80     GLES_CTS_DIR("aosp_mustpass/main/gles3-rotate-reverse-landscape.txt"),
81     GLES_CTS_DIR("aosp_mustpass/main/gles31-rotate-landscape.txt"),
82     GLES_CTS_DIR("aosp_mustpass/main/gles31-rotate-reverse-portrait.txt"),
83     GLES_CTS_DIR("aosp_mustpass/main/gles31-rotate-reverse-landscape.txt"),
84     GLES_CTS_DIR("aosp_mustpass/main/gles3-multisample.txt"),
85     GLES_CTS_DIR("aosp_mustpass/main/gles3-565-no-depth-no-stencil.txt"),
86     GLES_CTS_DIR("aosp_mustpass/main/gles31-multisample.txt"),
87     GLES_CTS_DIR("aosp_mustpass/main/gles31-565-no-depth-no-stencil.txt"),
88     GL_CTS_DIR("khronos_mustpass/main/gl46-main.txt"),
89 };
90 
91 const std::vector<const char *> gTestSuiteConfigParameters[] = {
92     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // egl
93     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles2
94     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles3
95     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles31
96     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles2_khr
97     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles3_khr
98     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles31_khr
99     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles32_khr
100     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles2_khr_noctx
101     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles32_khr_noctx
102     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles32_khr_single
103     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles3_rotate90
104     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles3_rotate180
105     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles3_rotate270
106     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles31_rotate90
107     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles31_rotate180
108     {"--deqp-gl-config-name=rgba8888d24s8ms0"},  // gles31_rotate270
109     {"--deqp-gl-config-name=rgba8888d24s8ms4"},  // gles3_multisample
110     {"--deqp-gl-config-name=rgb565d0s0ms0"},     // gles3_rgb565_no_depth_no_stencil
111     {"--deqp-gl-config-name=rgba8888d24s8ms4"},  // gles31_multisample
112     {"--deqp-gl-config-name=rgb565d0s0ms0"},     // gles31_rgb565_no_depth_no_stencil
113     {"--deqp-gl-config-name=rgba8888d24s8ms4"},  // gl46
114 };
115 
116 #undef GLES_CTS_DIR
117 #undef GL_CTS_DIR
118 
119 const char *gTestExpectationsFiles[] = {
120     "deqp_egl_test_expectations.txt",
121     "deqp_gles2_test_expectations.txt",
122     "deqp_gles3_test_expectations.txt",
123     "deqp_gles31_test_expectations.txt",
124     "deqp_khr_gles2_test_expectations.txt",
125     "deqp_khr_gles3_test_expectations.txt",
126     "deqp_khr_gles31_test_expectations.txt",
127     "deqp_khr_gles32_test_expectations.txt",
128     "deqp_khr_noctx_gles2_test_expectations.txt",
129     "deqp_khr_noctx_gles32_test_expectations.txt",
130     "deqp_khr_single_gles32_test_expectations.txt",
131     "deqp_gles3_rotate_test_expectations.txt",
132     "deqp_gles3_rotate_test_expectations.txt",
133     "deqp_gles3_rotate_test_expectations.txt",
134     "deqp_gles31_rotate_test_expectations.txt",
135     "deqp_gles31_rotate_test_expectations.txt",
136     "deqp_gles31_rotate_test_expectations.txt",
137     "deqp_gles3_multisample_test_expectations.txt",
138     "deqp_gles3_565_no_depth_no_stencil_test_expectations.txt",
139     "deqp_gles31_multisample_test_expectations.txt",
140     "deqp_gles31_565_no_depth_no_stencil_test_expectations.txt",
141     "deqp_gl46_test_expectations.txt",
142 };
143 
144 using APIInfo = std::pair<const char *, GPUTestConfig::API>;
145 
146 constexpr APIInfo kEGLDisplayAPIs[] = {
147     {"angle-d3d9", GPUTestConfig::kAPID3D9},
148     {"angle-d3d11", GPUTestConfig::kAPID3D11},
149     {"angle-d3d11-ref", GPUTestConfig::kAPID3D11},
150     {"angle-gl", GPUTestConfig::kAPIGLDesktop},
151     {"angle-gles", GPUTestConfig::kAPIGLES},
152     {"angle-metal", GPUTestConfig::kAPIMetal},
153     {"angle-null", GPUTestConfig::kAPIUnknown},
154     {"angle-swiftshader", GPUTestConfig::kAPISwiftShader},
155     {"angle-vulkan", GPUTestConfig::kAPIVulkan},
156     {"win32", GPUTestConfig::kAPIUnknown},
157     {"x11", GPUTestConfig::kAPIUnknown},
158 };
159 
160 constexpr char kdEQPEGLString[]             = "--deqp-egl-display-type=";
161 constexpr char kANGLEEGLString[]            = "--use-angle=";
162 constexpr char kANGLEPreRotation[]          = "--emulated-pre-rotation=";
163 constexpr char kdEQPCaseString[]            = "--deqp-case=";
164 constexpr char kVerboseString[]             = "--verbose";
165 constexpr char kRenderDocString[]           = "--renderdoc";
166 constexpr char kNoRenderDocString[]         = "--no-renderdoc";
167 constexpr char kdEQPFlagsPrefix[]           = "--deqp-";
168 constexpr char kGTestFilter[]               = "--gtest_filter=";
169 constexpr char kdEQPSurfaceWidth[]          = "--deqp-surface-width=";
170 constexpr char kdEQPSurfaceHeight[]         = "--deqp-surface-height=";
171 constexpr char kdEQPBaseSeed[]              = "--deqp-base-seed";
172 constexpr const char gdEQPLogImagesString[] = "--deqp-log-images=";
173 
174 // Use the config name defined in gTestSuiteConfigParameters by default
175 // If gEGLConfigNameFromCmdLine is overwritten by --deqp-gl-config-name passed from command
176 // line arguments, for example:
177 // out/Debug/angle_deqp_egl_tests --verbose --deqp-gl-config-name=rgba8888d24s8
178 // use gEGLConfigNameFromCmdLine (rgba8888d24s8) instead.
179 // Invalid --deqp-gl-config-name value passed from command line arguments will be caught by
180 // glu::parseConfigBitsFromName() defined in gluRenderConfig.cpp, and it will cause tests
181 // to fail
182 constexpr const char gdEQPEGLConfigNameString[] = "--deqp-gl-config-name=";
183 const char *gEGLConfigNameFromCmdLine           = "";
184 
185 angle::base::NoDestructor<std::vector<char>> gFilterStringBuffer;
186 
187 // For angle_deqp_gles3*_rotateN_tests, default gOptions.preRotation to N.
188 #if defined(ANGLE_DEQP_GLES3_ROTATE90_TESTS) || defined(ANGLE_DEQP_GLES31_ROTATE90_TESTS)
189 constexpr uint32_t kDefaultPreRotation = 90;
190 #elif defined(ANGLE_DEQP_GLES3_ROTATE180_TESTS) || defined(ANGLE_DEQP_GLES31_ROTATE180_TESTS)
191 constexpr uint32_t kDefaultPreRotation = 180;
192 #elif defined(ANGLE_DEQP_GLES3_ROTATE270_TESTS) || defined(ANGLE_DEQP_GLES31_ROTATE270_TESTS)
193 constexpr uint32_t kDefaultPreRotation = 270;
194 #else
195 constexpr uint32_t kDefaultPreRotation = 0;
196 #endif
197 
198 #if defined(ANGLE_TEST_ENABLE_RENDERDOC_CAPTURE)
199 constexpr bool kEnableRenderDocCapture = true;
200 #else
201 constexpr bool kEnableRenderDocCapture = false;
202 #endif
203 
204 const APIInfo *gInitAPI = nullptr;
205 dEQPOptions gOptions    = {
206     kDefaultPreRotation,      // preRotation
207     kEnableRenderDocCapture,  // enableRenderDocCapture
208 };
209 
210 std::vector<const char *> gdEQPForwardFlags;
211 
212 // Returns the default API for a platform.
GetDefaultAPIName()213 const char *GetDefaultAPIName()
214 {
215 #if defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_LINUX) || \
216     defined(ANGLE_PLATFORM_WINDOWS)
217     return "angle-vulkan";
218 #elif defined(ANGLE_PLATFORM_APPLE)
219     return "angle-gl";
220 #else
221 #    error Unknown platform.
222 #endif
223 }
224 
FindAPIInfo(const std::string & arg)225 const APIInfo *FindAPIInfo(const std::string &arg)
226 {
227     for (auto &displayAPI : kEGLDisplayAPIs)
228     {
229         if (arg == displayAPI.first)
230         {
231             return &displayAPI;
232         }
233     }
234     return nullptr;
235 }
236 
GetDefaultAPIInfo()237 const APIInfo *GetDefaultAPIInfo()
238 {
239     const APIInfo *defaultInfo = FindAPIInfo(GetDefaultAPIName());
240     ASSERT(defaultInfo);
241     return defaultInfo;
242 }
243 
GetTestStatLine(const std::string & key,const std::string & value)244 std::string GetTestStatLine(const std::string &key, const std::string &value)
245 {
246     return std::string(kInfoTag) + ": " + key + ": " + value + "\n";
247 }
248 
249 // During the CaseList initialization we cannot use the GTEST FAIL macro to quit the program
250 // because the initialization is called outside of tests the first time.
Die()251 void Die()
252 {
253     exit(EXIT_FAILURE);
254 }
255 
FindFileFromPath(const char * dirPath,const char * filePath)256 Optional<std::string> FindFileFromPath(const char *dirPath, const char *filePath)
257 {
258     std::stringstream strstr;
259     strstr << dirPath << filePath;
260     std::string path = strstr.str();
261 
262     constexpr size_t kMaxFoundPathLen = 1000;
263     char foundPath[kMaxFoundPathLen];
264     if (angle::FindTestDataPath(path.c_str(), foundPath, kMaxFoundPathLen))
265     {
266         return std::string(foundPath);
267     }
268 
269     return Optional<std::string>::Invalid();
270 }
271 
FindCaseListPath(size_t testModuleIndex)272 Optional<std::string> FindCaseListPath(size_t testModuleIndex)
273 {
274     return FindFileFromPath(kCTSRootPath, gCaseListFiles[testModuleIndex]);
275 }
276 
FindTestExpectationsPath(size_t testModuleIndex)277 Optional<std::string> FindTestExpectationsPath(size_t testModuleIndex)
278 {
279     return FindFileFromPath(kSupportPath, gTestExpectationsFiles[testModuleIndex]);
280 }
281 
GetTestModuleIndex()282 size_t GetTestModuleIndex()
283 {
284 #ifdef ANGLE_DEQP_EGL_TESTS
285     return 0;
286 #endif
287 
288 #ifdef ANGLE_DEQP_GLES2_TESTS
289     return 1;
290 #endif
291 
292 #ifdef ANGLE_DEQP_GLES3_TESTS
293     return 2;
294 #endif
295 
296 #ifdef ANGLE_DEQP_GLES31_TESTS
297     return 3;
298 #endif
299 
300 #ifdef ANGLE_DEQP_KHR_GLES2_TESTS
301     return 4;
302 #endif
303 
304 #ifdef ANGLE_DEQP_KHR_GLES3_TESTS
305     return 5;
306 #endif
307 
308 #ifdef ANGLE_DEQP_KHR_GLES31_TESTS
309     return 6;
310 #endif
311 
312 #ifdef ANGLE_DEQP_KHR_GLES32_TESTS
313     return 7;
314 #endif
315 
316 #ifdef ANGLE_DEQP_KHR_NOCTX_GLES2_TESTS
317     return 8;
318 #endif
319 
320 #ifdef ANGLE_DEQP_KHR_NOCTX_GLES32_TESTS
321     return 9;
322 #endif
323 
324 #ifdef ANGLE_DEQP_KHR_SINGLE_GLES32_TESTS
325     return 10;
326 #endif
327 
328 #ifdef ANGLE_DEQP_GLES3_ROTATE90_TESTS
329     return 11;
330 #endif
331 
332 #ifdef ANGLE_DEQP_GLES3_ROTATE180_TESTS
333     return 12;
334 #endif
335 
336 #ifdef ANGLE_DEQP_GLES3_ROTATE270_TESTS
337     return 13;
338 #endif
339 
340 #ifdef ANGLE_DEQP_GLES31_ROTATE90_TESTS
341     return 14;
342 #endif
343 
344 #ifdef ANGLE_DEQP_GLES31_ROTATE180_TESTS
345     return 15;
346 #endif
347 
348 #ifdef ANGLE_DEQP_GLES31_ROTATE270_TESTS
349     return 16;
350 #endif
351 
352 #ifdef ANGLE_DEQP_GLES3_MULTISAMPLE_TESTS
353     return 17;
354 #endif
355 
356 #ifdef ANGLE_DEQP_GLES3_565_NO_DEPTH_NO_STENCIL_TESTS
357     return 18;
358 #endif
359 
360 #ifdef ANGLE_DEQP_GLES31_MULTISAMPLE_TESTS
361     return 19;
362 #endif
363 
364 #ifdef ANGLE_DEQP_GLES31_565_NO_DEPTH_NO_STENCIL_TESTS
365     return 20;
366 #endif
367 
368 #ifdef ANGLE_DEQP_GL_TESTS
369     return 21;
370 #endif
371 }
372 
373 class dEQPCaseList
374 {
375   public:
376     dEQPCaseList(size_t testModuleIndex);
377 
378     struct CaseInfo
379     {
CaseInfoangle::__anon1e5fe5500111::dEQPCaseList::CaseInfo380         CaseInfo(const std::string &testNameIn, int expectationIn)
381             : testName(testNameIn), expectation(expectationIn)
382         {}
383 
384         std::string testName;
385         int expectation;
386     };
387 
388     void initialize();
389 
getCaseInfo(size_t caseIndex) const390     const CaseInfo &getCaseInfo(size_t caseIndex) const
391     {
392         ASSERT(mInitialized);
393         ASSERT(caseIndex < mCaseInfoList.size());
394         return mCaseInfoList[caseIndex];
395     }
396 
numCases() const397     size_t numCases() const
398     {
399         ASSERT(mInitialized);
400         return mCaseInfoList.size();
401     }
402 
403   private:
404     std::vector<CaseInfo> mCaseInfoList;
405     size_t mTestModuleIndex;
406     bool mInitialized = false;
407 };
408 
dEQPCaseList(size_t testModuleIndex)409 dEQPCaseList::dEQPCaseList(size_t testModuleIndex) : mTestModuleIndex(testModuleIndex) {}
410 
initialize()411 void dEQPCaseList::initialize()
412 {
413     if (mInitialized)
414     {
415         return;
416     }
417 
418     mInitialized = true;
419 
420     Optional<std::string> caseListPath = FindCaseListPath(mTestModuleIndex);
421     if (!caseListPath.valid())
422     {
423         std::cerr << "Failed to find case list file." << std::endl;
424         Die();
425     }
426 
427     Optional<std::string> testExpectationsPath = FindTestExpectationsPath(mTestModuleIndex);
428     if (!testExpectationsPath.valid())
429     {
430         std::cerr << "Failed to find test expectations file." << std::endl;
431         Die();
432     }
433 
434     GPUTestConfig::API api = GetDefaultAPIInfo()->second;
435     // Set the API from the command line, or using the default platform API.
436     if (gInitAPI)
437     {
438         api = gInitAPI->second;
439     }
440 
441     GPUTestConfig testConfig = GPUTestConfig(api, gOptions.preRotation);
442 
443 #if !defined(ANGLE_PLATFORM_ANDROID)
444     // Note: These prints mess up parsing of test list when running on Android.
445     std::cout << "Using test config with:" << std::endl;
446     for (uint32_t condition : testConfig.getConditions())
447     {
448         const char *name = GetConditionName(condition);
449         if (name != nullptr)
450         {
451             std::cout << "  " << name << std::endl;
452         }
453     }
454 #endif
455 
456     TestSuite *testSuite = TestSuite::GetInstance();
457 
458     if (!testSuite->loadTestExpectationsFromFileWithConfig(testConfig,
459                                                            testExpectationsPath.value()))
460     {
461         Die();
462     }
463 
464     std::ifstream caseListStream(caseListPath.value());
465     if (caseListStream.fail())
466     {
467         std::cerr << "Failed to load the case list." << std::endl;
468         Die();
469     }
470 
471     while (!caseListStream.eof())
472     {
473         std::string inString;
474         std::getline(caseListStream, inString);
475 
476         std::string testName = TrimString(inString, kWhitespaceASCII);
477         if (testName.empty())
478             continue;
479         int expectation = testSuite->getTestExpectation(testName);
480         mCaseInfoList.push_back(CaseInfo(testName, expectation));
481     }
482 
483     testSuite->logAnyUnusedTestExpectations();
484 }
485 
IsPassingResult(dEQPTestResult result)486 bool IsPassingResult(dEQPTestResult result)
487 {
488     // Check the global error flag for unexpected platform errors.
489     if (gGlobalError)
490     {
491         gGlobalError = false;
492         return false;
493     }
494 
495     switch (result)
496     {
497         case dEQPTestResult::Fail:
498         case dEQPTestResult::Exception:
499             return false;
500 
501         default:
502             return true;
503     }
504 }
505 
GetTestList(size_t testModuleIndex)506 const dEQPCaseList &GetTestList(size_t testModuleIndex)
507 {
508     static dEQPCaseList sCaseList(testModuleIndex);
509     sCaseList.initialize();
510     return sCaseList;
511 }
512 
GetTestCaseName(size_t testModuleIndex,size_t caseIndex)513 const std::string GetTestCaseName(size_t testModuleIndex, size_t caseIndex)
514 {
515     const auto &caseInfo = GetTestList(testModuleIndex).getCaseInfo(caseIndex);
516     return caseInfo.testName;
517 }
518 
519 class dEQPTestSuiteStats
520 {
521   public:
dEQPTestSuiteStats()522     dEQPTestSuiteStats() {}
523 
524   private:
525     void setUpTestStats();
526     void printTestStats();
527     void countTestResult(dEQPTestResult result);
528 
529     uint32_t mTestCount;
530     uint32_t mPassedTestCount;
531     uint32_t mFailedTestCount;
532     uint32_t mTestExceptionCount;
533     uint32_t mNotSupportedTestCount;
534     uint32_t mSkippedTestCount;
535 
536     std::vector<std::string> mUnexpectedFailed;
537     std::vector<std::string> mUnexpectedPasses;
538 
539     friend class dEQPTest;
540 };
541 
setUpTestStats()542 void dEQPTestSuiteStats::setUpTestStats()
543 {
544     mPassedTestCount       = 0;
545     mFailedTestCount       = 0;
546     mNotSupportedTestCount = 0;
547     mTestExceptionCount    = 0;
548     mTestCount             = 0;
549     mSkippedTestCount      = 0;
550     mUnexpectedPasses.clear();
551     mUnexpectedFailed.clear();
552 }
553 
printTestStats()554 void dEQPTestSuiteStats::printTestStats()
555 {
556     uint32_t crashedCount =
557         mTestCount - (mPassedTestCount + mFailedTestCount + mNotSupportedTestCount +
558                       mTestExceptionCount + mSkippedTestCount);
559 
560     std::cout << GetTestStatLine("Total", std::to_string(mTestCount));
561     std::cout << GetTestStatLine("Passed", std::to_string(mPassedTestCount));
562     std::cout << GetTestStatLine("Failed", std::to_string(mFailedTestCount));
563     std::cout << GetTestStatLine("Skipped", std::to_string(mSkippedTestCount));
564     std::cout << GetTestStatLine("Not Supported", std::to_string(mNotSupportedTestCount));
565     std::cout << GetTestStatLine("Exception", std::to_string(mTestExceptionCount));
566     std::cout << GetTestStatLine("Crashed", std::to_string(crashedCount));
567 
568     if (!mUnexpectedPasses.empty())
569     {
570         std::cout << GetTestStatLine("Unexpected Passed Count",
571                                      std::to_string(mUnexpectedPasses.size()));
572         for (const std::string &testName : mUnexpectedPasses)
573         {
574             std::cout << GetTestStatLine("Unexpected Passed Tests", testName);
575         }
576     }
577 
578     if (!mUnexpectedFailed.empty())
579     {
580         std::cout << GetTestStatLine("Unexpected Failed Count",
581                                      std::to_string(mUnexpectedFailed.size()));
582         for (const std::string &testName : mUnexpectedFailed)
583         {
584             std::cout << GetTestStatLine("Unexpected Failed Tests", testName);
585         }
586     }
587 }
588 
countTestResult(dEQPTestResult result)589 void dEQPTestSuiteStats::countTestResult(dEQPTestResult result)
590 {
591     switch (result)
592     {
593         case dEQPTestResult::Pass:
594             mPassedTestCount++;
595             break;
596         case dEQPTestResult::Fail:
597             mFailedTestCount++;
598             break;
599         case dEQPTestResult::NotSupported:
600             mNotSupportedTestCount++;
601             break;
602         case dEQPTestResult::Exception:
603             mTestExceptionCount++;
604             break;
605         default:
606             std::cerr << "Unexpected test result code: " << static_cast<int>(result) << "\n";
607             break;
608     }
609 }
610 
611 class dEQPTest : public testing::Test
612 {
613   public:
dEQPTest(size_t testModuleIndex,size_t caseIndex)614     dEQPTest(size_t testModuleIndex, size_t caseIndex)
615         : mTestModuleIndex(testModuleIndex), mTestCaseIndex(caseIndex)
616     {}
617 
618     static void SetUpTestSuite();
619     static void TearDownTestSuite();
620 
621   protected:
622     void TestBody() override;
623 
624   private:
625     size_t mTestModuleIndex = 0;
626     size_t mTestCaseIndex   = 0;
627 
628     static dEQPTestSuiteStats sTestSuiteData;
629 };
630 
631 dEQPTestSuiteStats dEQPTest::sTestSuiteData = dEQPTestSuiteStats();
632 
633 // static function called once before running all of dEQPTest under the same test suite
SetUpTestSuite()634 void dEQPTest::SetUpTestSuite()
635 {
636     sTestSuiteData.setUpTestStats();
637 
638     std::vector<const char *> argv;
639 
640     // Reserve one argument for the binary name.
641     argv.push_back("");
642 
643     // Add init api.
644     const char *targetApi    = gInitAPI ? gInitAPI->first : GetDefaultAPIName();
645     std::string apiArgString = std::string(kdEQPEGLString) + targetApi;
646     argv.push_back(apiArgString.c_str());
647 
648     std::string configNameFromCmdLineString =
649         std::string(gdEQPEGLConfigNameString) + gEGLConfigNameFromCmdLine;
650 
651     // Add test config parameters
652     for (const char *configParam : gTestSuiteConfigParameters[GetTestModuleIndex()])
653     {
654         // Check if we pass --deqp-gl-config-name from the command line, if yes, use the one from
655         // command line
656         if (std::strlen(gEGLConfigNameFromCmdLine) > 0 &&
657             std::strncmp(configParam, gdEQPEGLConfigNameString, strlen(gdEQPEGLConfigNameString)) ==
658                 0)
659         {
660             configParam = configNameFromCmdLineString.c_str();
661         }
662         argv.push_back(configParam);
663     }
664 
665     // Hide SwiftShader window to prevent a race with Xvfb causing hangs on test bots
666     if (gInitAPI && gInitAPI->second == GPUTestConfig::kAPISwiftShader)
667     {
668         argv.push_back("--deqp-visibility=hidden");
669     }
670 
671     TestSuite *testSuite = TestSuite::GetInstance();
672 
673     std::stringstream logNameStream;
674     logNameStream << "TestResults";
675     if (testSuite->getBatchId() != -1)
676     {
677         logNameStream << "-Batch" << std::setfill('0') << std::setw(3) << testSuite->getBatchId();
678     }
679     logNameStream << ".qpa";
680 
681     std::stringstream logArgStream;
682     logArgStream << "--deqp-log-filename="
683                  << testSuite->reserveTestArtifactPath(logNameStream.str());
684 
685     std::string logNameString = logArgStream.str();
686     argv.push_back(logNameString.c_str());
687 
688     if (!gLogImages)
689     {
690         argv.push_back("--deqp-log-images=disable");
691     }
692 
693     // Flushing during multi-process execution punishes HDDs. http://anglebug.com/5157
694     if (testSuite->getBatchId() != -1)
695     {
696         argv.push_back("--deqp-log-flush=disable");
697     }
698 
699     // Add any additional flags specified from command line to be forwarded to dEQP.
700     argv.insert(argv.end(), gdEQPForwardFlags.begin(), gdEQPForwardFlags.end());
701 
702     // Init the platform.
703     if (!deqp_libtester_init_platform(static_cast<int>(argv.size()), argv.data(),
704                                       reinterpret_cast<void *>(&HandlePlatformError), gOptions))
705     {
706         std::cout << "Aborting test due to dEQP initialization error." << std::endl;
707         exit(1);
708     }
709 }
710 
711 // static function called once after running all of dEQPTest under the same test suite
TearDownTestSuite()712 void dEQPTest::TearDownTestSuite()
713 {
714     sTestSuiteData.printTestStats();
715     deqp_libtester_shutdown_platform();
716 }
717 
718 // TestBody() is called once for each dEQPTest
TestBody()719 void dEQPTest::TestBody()
720 {
721     if (sTestSuiteData.mTestExceptionCount > 1)
722     {
723         std::cout << "Too many exceptions, skipping all remaining tests." << std::endl;
724         return;
725     }
726 
727     const auto &caseInfo = GetTestList(mTestModuleIndex).getCaseInfo(mTestCaseIndex);
728 
729     // Tests that crash exit the harness before collecting the result. To tally the number of
730     // crashed tests we track how many tests we "tried" to run.
731     sTestSuiteData.mTestCount++;
732 
733     if (caseInfo.expectation == GPUTestExpectationsParser::kGpuTestSkip)
734     {
735         sTestSuiteData.mSkippedTestCount++;
736         std::cout << "Test skipped.\n";
737         return;
738     }
739 
740     TestSuite *testSuite = TestSuite::GetInstance();
741     testSuite->maybeUpdateTestTimeout(caseInfo.expectation);
742 
743     gExpectError          = (caseInfo.expectation != GPUTestExpectationsParser::kGpuTestPass);
744     dEQPTestResult result = deqp_libtester_run(caseInfo.testName.c_str());
745 
746     bool testSucceeded = IsPassingResult(result);
747 
748     if (!testSucceeded && caseInfo.expectation == GPUTestExpectationsParser::kGpuTestFlaky)
749     {
750         result        = deqp_libtester_run(caseInfo.testName.c_str());
751         testSucceeded = IsPassingResult(result);
752     }
753 
754     sTestSuiteData.countTestResult(result);
755 
756     if (caseInfo.expectation == GPUTestExpectationsParser::kGpuTestPass ||
757         caseInfo.expectation == GPUTestExpectationsParser::kGpuTestFlaky)
758     {
759         EXPECT_TRUE(testSucceeded);
760 
761         if (!testSucceeded)
762         {
763             sTestSuiteData.mUnexpectedFailed.push_back(caseInfo.testName);
764         }
765     }
766     else if (testSucceeded)
767     {
768         std::cout << "Test expected to fail but passed!" << std::endl;
769         sTestSuiteData.mUnexpectedPasses.push_back(caseInfo.testName);
770     }
771 }
772 
HandleDisplayType(const char * displayTypeString)773 void HandleDisplayType(const char *displayTypeString)
774 {
775     std::stringstream argStream;
776 
777     if (gInitAPI)
778     {
779         std::cout << "Cannot specify two EGL displays!" << std::endl;
780         exit(1);
781     }
782 
783     argStream << displayTypeString;
784     std::string arg = argStream.str();
785     gInitAPI        = FindAPIInfo(arg);
786 
787     if (!gInitAPI && strncmp(displayTypeString, "angle-", strlen("angle-")) != 0)
788     {
789         std::stringstream argStream2;
790         argStream2 << "angle-" << displayTypeString;
791         std::string arg2 = argStream2.str();
792         gInitAPI         = FindAPIInfo(arg2);
793 
794         if (!gInitAPI)
795         {
796             std::cout << "Unknown API: " << displayTypeString << std::endl;
797             exit(1);
798         }
799     }
800 }
801 
HandlePreRotation(const char * preRotationString)802 void HandlePreRotation(const char *preRotationString)
803 {
804     std::istringstream argStream(preRotationString);
805 
806     uint32_t preRotation = 0;
807     argStream >> preRotation;
808 
809     if (!argStream ||
810         (preRotation != 0 && preRotation != 90 && preRotation != 180 && preRotation != 270))
811     {
812         std::cout << "Invalid PreRotation '" << preRotationString
813                   << "'; must be either 0, 90, 180 or 270" << std::endl;
814         exit(1);
815     }
816 
817     gOptions.preRotation = preRotation;
818 }
819 
HandleEGLConfigName(const char * configNameString)820 void HandleEGLConfigName(const char *configNameString)
821 {
822     gEGLConfigNameFromCmdLine = configNameString;
823 }
824 
825 // The --deqp-case flag takes a case expression that is parsed into a --gtest_filter. It
826 // converts the "dEQP" style names (functional.thing.*) into "GoogleTest" style names
827 // (functional_thing_*). Currently it does not handle multiple tests and multiple filters in
828 // different arguments.
HandleFilterArg(const char * filterString,int * argc,int argIndex,char ** argv)829 void HandleFilterArg(const char *filterString, int *argc, int argIndex, char **argv)
830 {
831     std::string googleTestFilter = ReplaceDashesWithQuestionMark(filterString);
832 
833     gFilterStringBuffer->resize(googleTestFilter.size() + 3 + strlen(kGTestFilter), 0);
834     std::fill(gFilterStringBuffer->begin(), gFilterStringBuffer->end(), 0);
835 
836     int bytesWritten = snprintf(gFilterStringBuffer->data(), gFilterStringBuffer->size() - 1,
837                                 "%s*%s", kGTestFilter, googleTestFilter.c_str());
838     if (bytesWritten <= 0 || static_cast<size_t>(bytesWritten) >= gFilterStringBuffer->size() - 1)
839     {
840         std::cout << "Error parsing filter string: " << filterString;
841         exit(1);
842     }
843 
844     argv[argIndex] = gFilterStringBuffer->data();
845 }
846 
HandleLogImages(const char * logImagesString)847 void HandleLogImages(const char *logImagesString)
848 {
849     if (strcmp(logImagesString, "enable") == 0)
850     {
851         gLogImages = true;
852     }
853     else if (strcmp(logImagesString, "disable") == 0)
854     {
855         gLogImages = false;
856     }
857     else
858     {
859         std::cout << "Error parsing log images setting. Use enable/disable.";
860         exit(1);
861     }
862 }
863 
RegisterGLCTSTests()864 void RegisterGLCTSTests()
865 {
866     size_t testModuleIndex = GetTestModuleIndex();
867 
868     const dEQPCaseList &caseList = GetTestList(testModuleIndex);
869 
870     for (size_t caseIndex = 0; caseIndex < caseList.numCases(); ++caseIndex)
871     {
872         auto factory = [testModuleIndex, caseIndex]() {
873             return new dEQPTest(testModuleIndex, caseIndex);
874         };
875 
876         const std::string testCaseName = GetTestCaseName(testModuleIndex, caseIndex);
877         size_t pos                     = testCaseName.find('.');
878         ASSERT(pos != std::string::npos);
879         // testCaseName comes from one of the mustpass files in gCaseListFiles.
880         // All of the testCaseName in the same mustpass file starts with the same testSuiteName
881         // prefix. Which mustpass file to load the set of testCaseName depends on testModuleIndex
882         // compiled into the deqp test application binary. For now, only one testModuleIndex is
883         // compiled in a deqp test application binary, meaning all of the tests invoked by same deqp
884         // test application binary are under the same test suite.
885         std::string testSuiteName = testCaseName.substr(0, pos);
886         std::string testName      = testCaseName.substr(pos + 1);
887         testing::RegisterTest(testSuiteName.c_str(), testName.c_str(), nullptr, nullptr, __FILE__,
888                               __LINE__, factory);
889     }
890 }
891 }  // anonymous namespace
892 
893 // Called from main() to process command-line arguments.
RunGLCTSTests(int * argc,char ** argv)894 int RunGLCTSTests(int *argc, char **argv)
895 {
896     int argIndex = 0;
897     while (argIndex < *argc)
898     {
899         if (strncmp(argv[argIndex], kdEQPEGLString, strlen(kdEQPEGLString)) == 0)
900         {
901             HandleDisplayType(argv[argIndex] + strlen(kdEQPEGLString));
902         }
903         else if (strncmp(argv[argIndex], kANGLEEGLString, strlen(kANGLEEGLString)) == 0)
904         {
905             HandleDisplayType(argv[argIndex] + strlen(kANGLEEGLString));
906         }
907         else if (strncmp(argv[argIndex], kANGLEPreRotation, strlen(kANGLEPreRotation)) == 0)
908         {
909             HandlePreRotation(argv[argIndex] + strlen(kANGLEPreRotation));
910         }
911         else if (strncmp(argv[argIndex], gdEQPEGLConfigNameString,
912                          strlen(gdEQPEGLConfigNameString)) == 0)
913         {
914             HandleEGLConfigName(argv[argIndex] + strlen(gdEQPEGLConfigNameString));
915         }
916         else if (strncmp(argv[argIndex], kdEQPCaseString, strlen(kdEQPCaseString)) == 0)
917         {
918             HandleFilterArg(argv[argIndex] + strlen(kdEQPCaseString), argc, argIndex, argv);
919         }
920         else if (strncmp(argv[argIndex], kGTestFilter, strlen(kGTestFilter)) == 0)
921         {
922             HandleFilterArg(argv[argIndex] + strlen(kGTestFilter), argc, argIndex, argv);
923         }
924         else if (strncmp(argv[argIndex], kVerboseString, strlen(kVerboseString)) == 0 ||
925                  strcmp(argv[argIndex], "-v") == 0)
926         {
927             gVerbose = true;
928         }
929         else if (strncmp(argv[argIndex], gdEQPLogImagesString, strlen(gdEQPLogImagesString)) == 0)
930         {
931             HandleLogImages(argv[argIndex] + strlen(gdEQPLogImagesString));
932         }
933         else if (strncmp(argv[argIndex], kRenderDocString, strlen(kRenderDocString)) == 0)
934         {
935             gOptions.enableRenderDocCapture = true;
936         }
937         else if (strncmp(argv[argIndex], kNoRenderDocString, strlen(kNoRenderDocString)) == 0)
938         {
939             gOptions.enableRenderDocCapture = false;
940         }
941         else if (strncmp(argv[argIndex], kdEQPFlagsPrefix, strlen(kdEQPFlagsPrefix)) == 0)
942         {
943             gdEQPForwardFlags.push_back(argv[argIndex]);
944         }
945         else if (strncmp(argv[argIndex], kdEQPSurfaceWidth, strlen(kdEQPSurfaceWidth)) == 0)
946         {
947             gdEQPForwardFlags.push_back(argv[argIndex]);
948         }
949         else if (strncmp(argv[argIndex], kdEQPSurfaceHeight, strlen(kdEQPSurfaceHeight)) == 0)
950         {
951             gdEQPForwardFlags.push_back(argv[argIndex]);
952         }
953         else if (strncmp(argv[argIndex], kdEQPBaseSeed, strlen(kdEQPBaseSeed)) == 0)
954         {
955             gdEQPForwardFlags.push_back(argv[argIndex]);
956         }
957         argIndex++;
958     }
959 
960     GPUTestConfig::API api = GetDefaultAPIInfo()->second;
961     if (gInitAPI)
962     {
963         api = gInitAPI->second;
964     }
965     if (gOptions.preRotation != 0 && api != GPUTestConfig::kAPIVulkan &&
966         api != GPUTestConfig::kAPISwiftShader)
967     {
968         std::cout << "PreRotation is only supported on Vulkan" << std::endl;
969         exit(1);
970     }
971 
972     angle::TestSuite testSuite(argc, argv, RegisterGLCTSTests);
973     return testSuite.run();
974 }
975 }  // namespace angle
976