Commit 58957f3d by Jamie Madill Committed by Commit Bot

Add option to run each test config in a separate process.

This CL adds a command line option to angle_end2end_tests that will iterate over all test configs. For each config it'll fork a new child process that will run only a single config. This will allow us to isolate each config to a specific child process. Hopefully this will reduce test flakiness due to driver issues with multiple configs. The command line option is "--separate-process-per-config". Note that there are about 25 configs right now. Bug: angleproject:3393 Change-Id: Ia117b371bbe159c1b0d28d82befffeb0f40467a9 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1591428 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org>
parent 80147d11
...@@ -28,6 +28,8 @@ bool PrependPathToEnvironmentVar(const char *variableName, const char *path); ...@@ -28,6 +28,8 @@ bool PrependPathToEnvironmentVar(const char *variableName, const char *path);
// Run an application and get the output. Gets a nullptr-terminated set of args to execute the // Run an application and get the output. Gets a nullptr-terminated set of args to execute the
// application with, and returns the stdout and stderr outputs as well as the exit code. // application with, and returns the stdout and stderr outputs as well as the exit code.
// //
// Pass nullptr for stdoutOut/stderrOut if you don't need to capture. exitCodeOut is required.
//
// Returns false if it fails to actually execute the application. // Returns false if it fails to actually execute the application.
bool RunApp(const std::vector<const char *> &args, bool RunApp(const std::vector<const char *> &args,
std::string *stdoutOut, std::string *stdoutOut,
......
...@@ -193,7 +193,11 @@ bool RunApp(const std::vector<const char *> &args, ...@@ -193,7 +193,11 @@ bool RunApp(const std::vector<const char *> &args,
{ {
startInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); startInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
} }
startInfo.dwFlags |= STARTF_USESTDHANDLES;
if (stderrOut || stdoutOut)
{
startInfo.dwFlags |= STARTF_USESTDHANDLES;
}
// Create the child process. // Create the child process.
PROCESS_INFORMATION processInfo = {}; PROCESS_INFORMATION processInfo = {};
......
...@@ -285,36 +285,85 @@ GLColor32F ReadColor32F(GLint x, GLint y) ...@@ -285,36 +285,85 @@ GLColor32F ReadColor32F(GLint x, GLint y)
} }
} // namespace angle } // namespace angle
using namespace angle;
namespace namespace
{ {
angle::PlatformMethods gDefaultPlatformMethods; PlatformMethods gDefaultPlatformMethods;
TestPlatformContext gPlatformContext; TestPlatformContext gPlatformContext;
// After a fixed number of iterations we reset the test window. This works around some driver bugs. // After a fixed number of iterations we reset the test window. This works around some driver bugs.
constexpr uint32_t kWindowReuseLimit = 50; constexpr uint32_t kWindowReuseLimit = 50;
constexpr char kUseConfig[] = "--use-config="; constexpr char kUseConfig[] = "--use-config=";
constexpr char kSeparateProcessPerConfig[] = "--separate-process-per-config";
bool RunSeparateProcessesForEachConfig(int *argc, char *argv[])
{
std::vector<const char *> commonArgs;
for (int argIndex = 0; argIndex < *argc; ++argIndex)
{
if (strncmp(argv[argIndex], kSeparateProcessPerConfig, strlen(kSeparateProcessPerConfig)) !=
0)
{
commonArgs.push_back(argv[argIndex]);
}
}
// Force GoogleTest init now so that we hit the test config init in angle_test_instantiate.cpp.
// After instantiation is finished we can gather a full list of enabled configs. Then we can
// iterate the list of configs to spawn a child process for each enabled config.
testing::InitGoogleTest(argc, argv);
std::vector<std::string> configNames = GetAvailableTestPlatformNames();
bool success = true;
for (const std::string &config : configNames)
{
std::stringstream strstr;
strstr << kUseConfig << config;
std::string configStr = strstr.str();
std::vector<const char *> childArgs = commonArgs;
childArgs.push_back(configStr.c_str());
int exitCode = 0;
if (!RunApp(childArgs, nullptr, nullptr, &exitCode))
{
std::cerr << "Launching child config " << config << " failed.\n";
}
else if (exitCode != 0)
{
std::cerr << "Child config " << config << " failed with exit code " << exitCode
<< ".\n";
success = false;
}
}
return success;
}
} // anonymous namespace } // anonymous namespace
// static // static
std::array<angle::Vector3, 6> ANGLETestBase::GetQuadVertices() std::array<Vector3, 6> ANGLETestBase::GetQuadVertices()
{ {
return angle::kQuadVertices; return kQuadVertices;
} }
// static // static
std::array<GLushort, 6> ANGLETestBase::GetQuadIndices() std::array<GLushort, 6> ANGLETestBase::GetQuadIndices()
{ {
return angle::kIndexedQuadIndices; return kIndexedQuadIndices;
} }
// static // static
std::array<angle::Vector3, 4> ANGLETestBase::GetIndexedQuadVertices() std::array<Vector3, 4> ANGLETestBase::GetIndexedQuadVertices()
{ {
return angle::kIndexedQuadVertices; return kIndexedQuadVertices;
} }
ANGLETestBase::ANGLETestBase(const angle::PlatformParameters &params) ANGLETestBase::ANGLETestBase(const PlatformParameters &params)
: mWidth(16), : mWidth(16),
mHeight(16), mHeight(16),
mIgnoreD3D11SDKLayersWarnings(false), mIgnoreD3D11SDKLayersWarnings(false),
...@@ -323,13 +372,13 @@ ANGLETestBase::ANGLETestBase(const angle::PlatformParameters &params) ...@@ -323,13 +372,13 @@ ANGLETestBase::ANGLETestBase(const angle::PlatformParameters &params)
m2DTexturedQuadProgram(0), m2DTexturedQuadProgram(0),
m3DTexturedQuadProgram(0), m3DTexturedQuadProgram(0),
mDeferContextInit(false), mDeferContextInit(false),
mAlwaysForceNewDisplay(angle::ShouldAlwaysForceNewDisplay()), mAlwaysForceNewDisplay(ShouldAlwaysForceNewDisplay()),
mForceNewDisplay(mAlwaysForceNewDisplay), mForceNewDisplay(mAlwaysForceNewDisplay),
mCurrentParams(nullptr), mCurrentParams(nullptr),
mFixture(nullptr) mFixture(nullptr)
{ {
// Override the default platform methods with the ANGLE test methods pointer. // Override the default platform methods with the ANGLE test methods pointer.
angle::PlatformParameters withMethods = params; PlatformParameters withMethods = params;
withMethods.eglParameters.platformMethods = &gDefaultPlatformMethods; withMethods.eglParameters.platformMethods = &gDefaultPlatformMethods;
auto iter = gFixtures.find(withMethods); auto iter = gFixtures.find(withMethods);
...@@ -379,24 +428,24 @@ void ANGLETestBase::initOSWindow() ...@@ -379,24 +428,24 @@ void ANGLETestBase::initOSWindow()
} }
// On Linux we must keep the test windows visible. On Windows it doesn't seem to need it. // On Linux we must keep the test windows visible. On Windows it doesn't seem to need it.
mFixture->osWindow->setVisible(!angle::IsWindows()); mFixture->osWindow->setVisible(!IsWindows());
switch (mCurrentParams->driver) switch (mCurrentParams->driver)
{ {
case angle::GLESDriverType::AngleEGL: case GLESDriverType::AngleEGL:
{ {
mFixture->eglWindow = mFixture->eglWindow =
EGLWindow::New(mCurrentParams->majorVersion, mCurrentParams->minorVersion); EGLWindow::New(mCurrentParams->majorVersion, mCurrentParams->minorVersion);
break; break;
} }
case angle::GLESDriverType::SystemEGL: case GLESDriverType::SystemEGL:
{ {
std::cerr << "Unsupported driver." << std::endl; std::cerr << "Unsupported driver." << std::endl;
break; break;
} }
case angle::GLESDriverType::SystemWGL: case GLESDriverType::SystemWGL:
{ {
// WGL tests are currently disabled. // WGL tests are currently disabled.
std::cerr << "Unsupported driver." << std::endl; std::cerr << "Unsupported driver." << std::endl;
...@@ -427,21 +476,21 @@ ANGLETestBase::~ANGLETestBase() ...@@ -427,21 +476,21 @@ ANGLETestBase::~ANGLETestBase()
void ANGLETestBase::ANGLETestSetUp() void ANGLETestBase::ANGLETestSetUp()
{ {
gDefaultPlatformMethods.overrideWorkaroundsD3D = angle::TestPlatform_overrideWorkaroundsD3D; gDefaultPlatformMethods.overrideWorkaroundsD3D = TestPlatform_overrideWorkaroundsD3D;
gDefaultPlatformMethods.overrideFeaturesVk = angle::TestPlatform_overrideFeaturesVk; gDefaultPlatformMethods.overrideFeaturesVk = TestPlatform_overrideFeaturesVk;
gDefaultPlatformMethods.logError = angle::TestPlatform_logError; gDefaultPlatformMethods.logError = TestPlatform_logError;
gDefaultPlatformMethods.logWarning = angle::TestPlatform_logWarning; gDefaultPlatformMethods.logWarning = TestPlatform_logWarning;
gDefaultPlatformMethods.logInfo = angle::TestPlatform_logInfo; gDefaultPlatformMethods.logInfo = TestPlatform_logInfo;
gDefaultPlatformMethods.context = &gPlatformContext; gDefaultPlatformMethods.context = &gPlatformContext;
gPlatformContext.ignoreMessages = false; gPlatformContext.ignoreMessages = false;
gPlatformContext.warningsAsErrors = false; gPlatformContext.warningsAsErrors = false;
gPlatformContext.currentTest = this; gPlatformContext.currentTest = this;
if (angle::IsWindows()) if (IsWindows())
{ {
const auto &info = testing::UnitTest::GetInstance()->current_test_info(); const auto &info = testing::UnitTest::GetInstance()->current_test_info();
angle::WriteDebugMessage("Entering %s.%s\n", info->test_case_name(), info->name()); WriteDebugMessage("Entering %s.%s\n", info->test_case_name(), info->name());
} }
if (mCurrentParams->noFixture) if (mCurrentParams->noFixture)
...@@ -451,8 +500,8 @@ void ANGLETestBase::ANGLETestSetUp() ...@@ -451,8 +500,8 @@ void ANGLETestBase::ANGLETestSetUp()
ANGLETestEnvironment::GetEGLLibrary()->getAs("eglGetProcAddress", &getProcAddress); ANGLETestEnvironment::GetEGLLibrary()->getAs("eglGetProcAddress", &getProcAddress);
ASSERT_NE(nullptr, getProcAddress); ASSERT_NE(nullptr, getProcAddress);
angle::LoadEGL(getProcAddress); LoadEGL(getProcAddress);
angle::LoadGLES(getProcAddress); LoadGLES(getProcAddress);
#endif // defined(ANGLE_USE_UTIL_LOADER) #endif // defined(ANGLE_USE_UTIL_LOADER)
return; return;
} }
...@@ -521,10 +570,10 @@ void ANGLETestBase::ANGLETestTearDown() ...@@ -521,10 +570,10 @@ void ANGLETestBase::ANGLETestTearDown()
{ {
gPlatformContext.currentTest = nullptr; gPlatformContext.currentTest = nullptr;
if (angle::IsWindows()) if (IsWindows())
{ {
const testing::TestInfo *info = testing::UnitTest::GetInstance()->current_test_info(); const testing::TestInfo *info = testing::UnitTest::GetInstance()->current_test_info();
angle::WriteDebugMessage("Exiting %s.%s\n", info->test_case_name(), info->name()); WriteDebugMessage("Exiting %s.%s\n", info->test_case_name(), info->name());
} }
if (mCurrentParams->noFixture) if (mCurrentParams->noFixture)
...@@ -583,7 +632,7 @@ void ANGLETestBase::setupQuadVertexBuffer(GLfloat positionAttribZ, GLfloat posit ...@@ -583,7 +632,7 @@ void ANGLETestBase::setupQuadVertexBuffer(GLfloat positionAttribZ, GLfloat posit
} }
auto quadVertices = GetQuadVertices(); auto quadVertices = GetQuadVertices();
for (angle::Vector3 &vertex : quadVertices) for (Vector3 &vertex : quadVertices)
{ {
vertex.x() *= positionAttribXYScale; vertex.x() *= positionAttribXYScale;
vertex.y() *= positionAttribXYScale; vertex.y() *= positionAttribXYScale;
...@@ -602,8 +651,8 @@ void ANGLETestBase::setupIndexedQuadVertexBuffer(GLfloat positionAttribZ, ...@@ -602,8 +651,8 @@ void ANGLETestBase::setupIndexedQuadVertexBuffer(GLfloat positionAttribZ,
glGenBuffers(1, &mQuadVertexBuffer); glGenBuffers(1, &mQuadVertexBuffer);
} }
auto quadVertices = angle::kIndexedQuadVertices; auto quadVertices = kIndexedQuadVertices;
for (angle::Vector3 &vertex : quadVertices) for (Vector3 &vertex : quadVertices)
{ {
vertex.x() *= positionAttribXYScale; vertex.x() *= positionAttribXYScale;
vertex.y() *= positionAttribXYScale; vertex.y() *= positionAttribXYScale;
...@@ -622,8 +671,8 @@ void ANGLETestBase::setupIndexedQuadIndexBuffer() ...@@ -622,8 +671,8 @@ void ANGLETestBase::setupIndexedQuadIndexBuffer()
} }
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadIndexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadIndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(angle::kIndexedQuadIndices), glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(kIndexedQuadIndices), kIndexedQuadIndices.data(),
angle::kIndexedQuadIndices.data(), GL_STATIC_DRAW); GL_STATIC_DRAW);
} }
// static // static
...@@ -684,7 +733,7 @@ void ANGLETestBase::drawQuad(GLuint program, ...@@ -684,7 +733,7 @@ void ANGLETestBase::drawQuad(GLuint program,
GLint positionLocation = glGetAttribLocation(program, positionAttribName.c_str()); GLint positionLocation = glGetAttribLocation(program, positionAttribName.c_str());
std::array<angle::Vector3, 6> quadVertices; std::array<Vector3, 6> quadVertices;
if (useVertexBuffer) if (useVertexBuffer)
{ {
...@@ -695,7 +744,7 @@ void ANGLETestBase::drawQuad(GLuint program, ...@@ -695,7 +744,7 @@ void ANGLETestBase::drawQuad(GLuint program,
else else
{ {
quadVertices = GetQuadVertices(); quadVertices = GetQuadVertices();
for (angle::Vector3 &vertex : quadVertices) for (Vector3 &vertex : quadVertices)
{ {
vertex.x() *= positionAttribXYScale; vertex.x() *= positionAttribXYScale;
vertex.y() *= positionAttribXYScale; vertex.y() *= positionAttribXYScale;
...@@ -794,7 +843,7 @@ void ANGLETestBase::drawIndexedQuad(GLuint program, ...@@ -794,7 +843,7 @@ void ANGLETestBase::drawIndexedQuad(GLuint program,
} }
else else
{ {
indices = angle::kIndexedQuadIndices.data(); indices = kIndexedQuadIndices.data();
} }
if (!restrictedRange) if (!restrictedRange)
...@@ -1096,8 +1145,7 @@ void ANGLETestBase::setRobustResourceInit(bool enabled) ...@@ -1096,8 +1145,7 @@ void ANGLETestBase::setRobustResourceInit(bool enabled)
mFixture->configParams.robustResourceInit = enabled; mFixture->configParams.robustResourceInit = enabled;
} }
void ANGLETestBase::setContextProgramCacheEnabled(bool enabled, void ANGLETestBase::setContextProgramCacheEnabled(bool enabled, CacheProgramFunc cacheProgramFunc)
angle::CacheProgramFunc cacheProgramFunc)
{ {
mFixture->configParams.contextProgramCacheEnabled = enabled; mFixture->configParams.contextProgramCacheEnabled = enabled;
gDefaultPlatformMethods.cacheProgram = cacheProgramFunc; gDefaultPlatformMethods.cacheProgram = cacheProgramFunc;
...@@ -1284,30 +1332,30 @@ OSWindow *ANGLETestBase::mOSWindowSingleton = nullptr; ...@@ -1284,30 +1332,30 @@ OSWindow *ANGLETestBase::mOSWindowSingleton = nullptr;
std::map<angle::PlatformParameters, ANGLETestBase::TestFixture> ANGLETestBase::gFixtures; std::map<angle::PlatformParameters, ANGLETestBase::TestFixture> ANGLETestBase::gFixtures;
Optional<EGLint> ANGLETestBase::mLastRendererType; Optional<EGLint> ANGLETestBase::mLastRendererType;
std::unique_ptr<angle::Library> ANGLETestEnvironment::gEGLLibrary; std::unique_ptr<Library> ANGLETestEnvironment::gEGLLibrary;
std::unique_ptr<angle::Library> ANGLETestEnvironment::gWGLLibrary; std::unique_ptr<Library> ANGLETestEnvironment::gWGLLibrary;
void ANGLETestEnvironment::SetUp() {} void ANGLETestEnvironment::SetUp() {}
void ANGLETestEnvironment::TearDown() {} void ANGLETestEnvironment::TearDown() {}
angle::Library *ANGLETestEnvironment::GetEGLLibrary() Library *ANGLETestEnvironment::GetEGLLibrary()
{ {
#if defined(ANGLE_USE_UTIL_LOADER) #if defined(ANGLE_USE_UTIL_LOADER)
if (!gEGLLibrary) if (!gEGLLibrary)
{ {
gEGLLibrary.reset(angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME)); gEGLLibrary.reset(OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME));
} }
#endif // defined(ANGLE_USE_UTIL_LOADER) #endif // defined(ANGLE_USE_UTIL_LOADER)
return gEGLLibrary.get(); return gEGLLibrary.get();
} }
angle::Library *ANGLETestEnvironment::GetWGLLibrary() Library *ANGLETestEnvironment::GetWGLLibrary()
{ {
#if defined(ANGLE_USE_UTIL_LOADER) && defined(ANGLE_PLATFORM_WINDOWS) #if defined(ANGLE_USE_UTIL_LOADER) && defined(ANGLE_PLATFORM_WINDOWS)
if (!gWGLLibrary) if (!gWGLLibrary)
{ {
gWGLLibrary.reset(angle::OpenSharedLibrary("opengl32")); gWGLLibrary.reset(OpenSharedLibrary("opengl32"));
} }
#endif // defined(ANGLE_USE_UTIL_LOADER) && defined(ANGLE_PLATFORM_WINDOWS) #endif // defined(ANGLE_USE_UTIL_LOADER) && defined(ANGLE_PLATFORM_WINDOWS)
return gWGLLibrary.get(); return gWGLLibrary.get();
...@@ -1321,7 +1369,31 @@ void ANGLEProcessTestArgs(int *argc, char *argv[]) ...@@ -1321,7 +1369,31 @@ void ANGLEProcessTestArgs(int *argc, char *argv[])
{ {
if (strncmp(argv[argIndex], kUseConfig, strlen(kUseConfig)) == 0) if (strncmp(argv[argIndex], kUseConfig, strlen(kUseConfig)) == 0)
{ {
angle::gSelectedConfig = std::string(argv[argIndex] + strlen(kUseConfig)); gSelectedConfig = std::string(argv[argIndex] + strlen(kUseConfig));
}
if (strncmp(argv[argIndex], kSeparateProcessPerConfig, strlen(kSeparateProcessPerConfig)) ==
0)
{
gSeparateProcessPerConfig = true;
}
}
if (gSeparateProcessPerConfig)
{
if (!gSelectedConfig.empty())
{
std::cout << "Cannot use both a single test config and separate processes.\n";
exit(1);
}
if (RunSeparateProcessesForEachConfig(argc, argv))
{
exit(0);
}
else
{
std::cout << "Some subprocesses failed.\n";
exit(1);
} }
} }
} }
......
...@@ -67,9 +67,12 @@ bool IsNativeConfigSupported(const PlatformParameters &param, OSWindow *osWindow ...@@ -67,9 +67,12 @@ bool IsNativeConfigSupported(const PlatformParameters &param, OSWindow *osWindow
// Not yet implemented. // Not yet implemented.
return false; return false;
} }
std::map<PlatformParameters, bool> gParamAvailabilityCache;
} // namespace } // namespace
std::string gSelectedConfig; std::string gSelectedConfig;
bool gSeparateProcessPerConfig = false;
SystemInfo *GetTestSystemInfo() SystemInfo *GetTestSystemInfo()
{ {
...@@ -84,7 +87,8 @@ SystemInfo *GetTestSystemInfo() ...@@ -84,7 +87,8 @@ SystemInfo *GetTestSystemInfo()
// Print complete system info when available. // Print complete system info when available.
// Seems to trip up Android test expectation parsing. // Seems to trip up Android test expectation parsing.
if (!IsAndroid()) // Also don't print info when a config is selected to prevent test spam.
if (!IsAndroid() && gSelectedConfig.empty())
{ {
PrintSystemInfo(*sSystemInfo); PrintSystemInfo(*sSystemInfo);
} }
...@@ -408,48 +412,80 @@ bool IsPlatformAvailable(const PlatformParameters &param) ...@@ -408,48 +412,80 @@ bool IsPlatformAvailable(const PlatformParameters &param)
return false; return false;
} }
static std::map<PlatformParameters, bool> paramAvailabilityCache;
auto iter = paramAvailabilityCache.find(param);
if (iter != paramAvailabilityCache.end())
{
return iter->second;
}
bool result = false; bool result = false;
if (!gSelectedConfig.empty()) auto iter = gParamAvailabilityCache.find(param);
if (iter != gParamAvailabilityCache.end())
{ {
std::stringstream strstr; result = iter->second;
strstr << param;
if (strstr.str() == gSelectedConfig)
{
result = true;
}
} }
else else
{ {
const SystemInfo *systemInfo = GetTestSystemInfo(); if (!gSelectedConfig.empty())
if (systemInfo)
{ {
result = IsConfigWhitelisted(*systemInfo, param); std::stringstream strstr;
strstr << param;
if (strstr.str() == gSelectedConfig)
{
result = true;
}
} }
else else
{ {
result = IsConfigSupported(param); const SystemInfo *systemInfo = GetTestSystemInfo();
if (systemInfo)
{
result = IsConfigWhitelisted(*systemInfo, param);
}
else
{
result = IsConfigSupported(param);
}
} }
gParamAvailabilityCache[param] = result;
// Enable this unconditionally to print available platforms.
if (!gSelectedConfig.empty())
{
if (result)
{
std::cout << "Test Config: " << param << "\n";
}
}
else if (!result)
{
std::cout << "Skipping tests using configuration " << param
<< " because it is not available.\n";
}
}
// Disable all tests in the parent process when running child processes.
if (gSeparateProcessPerConfig)
{
return false;
} }
return result;
}
paramAvailabilityCache[param] = result; std::vector<std::string> GetAvailableTestPlatformNames()
{
std::vector<std::string> platformNames;
if (!result) for (const auto &iter : gParamAvailabilityCache)
{ {
std::cout << "Skipping tests using configuration " << param if (iter.second)
<< " because it is not available." << std::endl; {
std::stringstream strstr;
strstr << iter.first;
platformNames.push_back(strstr.str());
}
} }
// Uncomment this to print available platforms. // Keep the list sorted.
// std::cout << "Platform: " << param << " (" << paramAvailabilityCache.size() << ")\n"; std::sort(platformNames.begin(), platformNames.end());
return result;
return platformNames;
} }
} // namespace angle } // namespace angle
...@@ -122,8 +122,15 @@ bool IsConfigSupported(const PlatformParameters &param); ...@@ -122,8 +122,15 @@ bool IsConfigSupported(const PlatformParameters &param);
// Returns shared test system information. Can be used globally in the tests. // Returns shared test system information. Can be used globally in the tests.
SystemInfo *GetTestSystemInfo(); SystemInfo *GetTestSystemInfo();
// Returns a list of all enabled test platform names. For use in configuration enumeration.
std::vector<std::string> GetAvailableTestPlatformNames();
// Active config (e.g. ES2_Vulkan). // Active config (e.g. ES2_Vulkan).
extern std::string gSelectedConfig; extern std::string gSelectedConfig;
// Use a separate isolated process per test config. This works around driver flakiness when using
// multiple APIs/windows/etc in the same process.
extern bool gSeparateProcessPerConfig;
} // namespace angle } // namespace angle
#endif // ANGLE_TEST_INSTANTIATE_H_ #endif // ANGLE_TEST_INSTANTIATE_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment