// // Copyright 2015 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // deqp_libtester_main.cpp: Entry point for tester DLL. #include #include #include "angle_deqp_libtester.h" #include "common/angleutils.h" #include "deMath.h" #include "deUniquePtr.hpp" #include "tcuApp.hpp" #include "tcuCommandLine.hpp" #include "tcuDefs.hpp" #include "tcuPlatform.hpp" #include "tcuRandomOrderExecutor.h" #include "tcuResource.hpp" #include "tcuTestLog.hpp" #include "system_utils.h" #if (DE_OS == DE_OS_WIN32) #include #elif (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX) #include #include #include #elif (DE_OS == DE_OS_ANDROID) #include #endif tcu::Platform *createPlatform(); namespace { tcu::Platform *g_platform = nullptr; tcu::CommandLine *g_cmdLine = nullptr; tcu::DirArchive *g_archive = nullptr; tcu::TestLog *g_log = nullptr; tcu::TestContext *g_testCtx = nullptr; tcu::TestPackageRoot *g_root = nullptr; tcu::RandomOrderExecutor *g_executor = nullptr; const char *g_dEQPDataSearchDirs[] = { "data", "third_party/deqp/data", "../third_party/deqp/src/data", "deqp_support/data", "third_party/deqp/src/data", "../../third_party/deqp/src/data", "../../../third_party/deqp/src/data", "../../sdcard/chromium_tests_root/third_party/deqp/src/data", }; // TODO(jmadill): upstream to dEQP? #if (DE_OS == DE_OS_WIN32) deBool deIsDir(const char *filename) { WIN32_FILE_ATTRIBUTE_DATA fileInformation; BOOL result = GetFileAttributesExA(filename, GetFileExInfoStandard, &fileInformation); if (result) { DWORD attribs = fileInformation.dwFileAttributes; return (attribs != INVALID_FILE_ATTRIBUTES) && ((attribs & FILE_ATTRIBUTE_DIRECTORY) > 0); } return false; } #elif (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_ANDROID) deBool deIsDir(const char *filename) { struct stat st; int result = stat(filename, &st); return result == 0 && ((st.st_mode & S_IFDIR) == S_IFDIR); } #else #error TODO(jmadill): support other platforms #endif bool FindDataDir(std::string *dataDirOut) { for (auto searchDir : g_dEQPDataSearchDirs) { if (deIsDir((std::string(searchDir) + "/gles2").c_str())) { *dataDirOut = searchDir; return true; } std::stringstream dirStream; dirStream << angle::GetExecutableDirectory() << "/" << searchDir; std::string dataDir = dirStream.str(); dirStream << "/gles2"; std::string searchPath = dirStream.str(); if (deIsDir(searchPath.c_str())) { *dataDirOut = dataDir; return true; } } return false; } std::string GetLogFileName(std::string deqpDataDir) { #if (DE_OS == DE_OS_ANDROID) // On Android executable dir is not writable, so use data dir instead return deqpDataDir + "/" + g_cmdLine->getLogFileName(); #else return g_cmdLine->getLogFileName(); #endif } } // anonymous namespace ANGLE_LIBTESTER_EXPORT bool deqp_libtester_init_platform(int argc, const char *argv[]) { try { #if (DE_OS != DE_OS_WIN32) // Set stdout to line-buffered mode (will be fully buffered by default if stdout is pipe). setvbuf(stdout, DE_NULL, _IOLBF, 4 * 1024); #endif g_platform = createPlatform(); if (!deSetRoundingMode(DE_ROUNDINGMODE_TO_NEAREST)) { std::cout << "Failed to set floating point rounding mode." << std::endl; return false; } std::string deqpDataDir; if (!FindDataDir(&deqpDataDir)) { std::cout << "Failed to find dEQP data directory." << std::endl; return false; } g_cmdLine = new tcu::CommandLine(argc, argv); g_archive = new tcu::DirArchive(deqpDataDir.c_str()); g_log = new tcu::TestLog(GetLogFileName(deqpDataDir).c_str(), g_cmdLine->getLogFlags()); g_testCtx = new tcu::TestContext(*g_platform, *g_archive, *g_log, *g_cmdLine, DE_NULL); g_root = new tcu::TestPackageRoot(*g_testCtx, tcu::TestPackageRegistry::getSingleton()); g_executor = new tcu::RandomOrderExecutor(*g_root, *g_testCtx); } catch (const std::exception& e) { tcu::die("%s", e.what()); return false; } return true; } // Exported to the tester app. ANGLE_LIBTESTER_EXPORT int deqp_libtester_main(int argc, const char *argv[]) { if (!deqp_libtester_init_platform(argc, argv)) { tcu::die("Could not initialize the dEQP platform"); } try { de::UniquePtr app(new tcu::App(*g_platform, *g_archive, *g_log, *g_cmdLine)); // Main loop. for (;;) { if (!app->iterate()) break; } } catch (const std::exception &e) { deqp_libtester_shutdown_platform(); tcu::die("%s", e.what()); } deqp_libtester_shutdown_platform(); return 0; } 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 && !deqp_libtester_init_platform(1, &emptyString)) { tcu::die("Failed to initialize platform."); } try { // Poll platform events const bool platformOk = g_platform->processEvents(); if (platformOk) { const tcu::TestStatus &result = g_executor->execute(caseName); switch (result.getCode()) { case QP_TEST_RESULT_PASS: case QP_TEST_RESULT_NOT_SUPPORTED: return true; case QP_TEST_RESULT_QUALITY_WARNING: std::cout << "Quality warning! " << result.getDescription() << std::endl; return true; case QP_TEST_RESULT_COMPATIBILITY_WARNING: std::cout << "Compatiblity warning! " << result.getDescription() << std::endl; return true; default: return false; } } else { std::cout << "Aborted test!" << std::endl; } } catch (const std::exception &e) { std::cout << "Exception running test: " << e.what() << std::endl; } return false; }