Reuse angle_end2end_test windows and displays.

This both speeds up test execution and cuts down on the number of new
windows and displays created for a test config. This feature is only
currently enabled for Windows NVIDIA and Intel. On every other config
there were blocking issues that would need investigation. Several tests
were manually flagged as needed new displays on each iteration to
prevent test flakiness.

This feature might fix the issues with Intel test flakiness that have
been prominent on the ANGLE CQ.

WGL configurations have also been removed from ANGLE tests. So this
removes more of the code from ANGLETest.cpp.

Bug: angleproject:3261
Change-Id: Ic2864d4806ad38e0eeaa3c0afcd54ae1c548090f
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1520995
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
diff --git a/src/libANGLE/validationEGL.cpp b/src/libANGLE/validationEGL.cpp
index b17571d..a092d0a 100644
--- a/src/libANGLE/validationEGL.cpp
+++ b/src/libANGLE/validationEGL.cpp
@@ -2869,11 +2869,7 @@
                                        EGLint *rects,
                                        EGLint n_rects)
 {
-    Error error = ValidateSurface(display, surface);
-    if (error.isError())
-    {
-        return error;
-    }
+    ANGLE_TRY(ValidateSurface(display, surface));
 
     if (!display->getExtensions().swapBuffersWithDamage)
     {
diff --git a/src/tests/egl_tests/EGLBlobCacheTest.cpp b/src/tests/egl_tests/EGLBlobCacheTest.cpp
index cecff26..544a335 100644
--- a/src/tests/egl_tests/EGLBlobCacheTest.cpp
+++ b/src/tests/egl_tests/EGLBlobCacheTest.cpp
@@ -78,7 +78,11 @@
 class EGLBlobCacheTest : public ANGLETest
 {
   protected:
-    EGLBlobCacheTest() : mHasBlobCache(false) {}
+    EGLBlobCacheTest() : mHasBlobCache(false)
+    {
+        // Force disply caching off. Blob cache functions require it.
+        forceNewDisplay();
+    }
 
     void SetUp() override
     {
@@ -88,8 +92,6 @@
         mHasBlobCache      = eglDisplayExtensionEnabled(display, kEGLExtName);
     }
 
-    void TearDown() override { ANGLETest::TearDown(); }
-
     bool programBinaryAvailable()
     {
         return (getClientMajorVersion() >= 3 || extensionEnabled("GL_OES_get_program_binary"));
@@ -103,7 +105,7 @@
 {
     EGLDisplay display = getEGLWindow()->getDisplay();
 
-    EXPECT_EQ(true, mHasBlobCache);
+    EXPECT_TRUE(mHasBlobCache);
     eglSetBlobCacheFuncsANDROID(display, SetBlob, GetBlob);
     ASSERT_EGL_SUCCESS();
 
@@ -172,7 +174,7 @@
 // Tests error conditions of the APIs.
 TEST_P(EGLBlobCacheTest, NegativeAPI)
 {
-    EXPECT_EQ(true, mHasBlobCache);
+    EXPECT_TRUE(mHasBlobCache);
 
     // Test bad display
     eglSetBlobCacheFuncsANDROID(EGL_NO_DISPLAY, nullptr, nullptr);
diff --git a/src/tests/egl_tests/EGLProgramCacheControlTest.cpp b/src/tests/egl_tests/EGLProgramCacheControlTest.cpp
index 17bafac..2c39b79 100644
--- a/src/tests/egl_tests/EGLProgramCacheControlTest.cpp
+++ b/src/tests/egl_tests/EGLProgramCacheControlTest.cpp
@@ -31,25 +31,34 @@
     }
 
   protected:
-    EGLProgramCacheControlTest() { setDeferContextInit(true); }
+    EGLProgramCacheControlTest()
+    {
+        // Test flakiness was noticed when reusing displays.
+        forceNewDisplay();
+        setDeferContextInit(true);
+    }
 
     void SetUp() override
     {
-        mPlatformMethods.cacheProgram = &TestCacheProgram;
+        setContextProgramCacheEnabled(true, &TestCacheProgram);
 
         ANGLETest::SetUp();
 
         if (extensionAvailable())
         {
             EGLDisplay display = getEGLWindow()->getDisplay();
-            setContextProgramCacheEnabled(true);
             eglProgramCacheResizeANGLE(display, kEnabledCacheSize, EGL_PROGRAM_CACHE_RESIZE_ANGLE);
+            ASSERT_EGL_SUCCESS();
         }
 
-        getEGLWindow()->initializeContext();
+        ASSERT_TRUE(getEGLWindow()->initializeContext());
     }
 
-    void TearDown() override { ANGLETest::TearDown(); }
+    void TearDown() override
+    {
+        setContextProgramCacheEnabled(false, angle::DefaultCacheProgram);
+        ANGLETest::TearDown();
+    }
 
     bool extensionAvailable()
     {
diff --git a/src/tests/gl_tests/DrawBuffersTest.cpp b/src/tests/gl_tests/DrawBuffersTest.cpp
index 4870c64..d4b2bb3 100644
--- a/src/tests/gl_tests/DrawBuffersTest.cpp
+++ b/src/tests/gl_tests/DrawBuffersTest.cpp
@@ -57,7 +57,7 @@
         }
 
         // This test seems to fail on an nVidia machine when the window is hidden
-        SetWindowVisible(true);
+        setWindowVisible(true);
 
         glGenFramebuffers(1, &mFBO);
         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFBO);
diff --git a/src/tests/gl_tests/InstancingTest.cpp b/src/tests/gl_tests/InstancingTest.cpp
index dba0f76..7190603 100644
--- a/src/tests/gl_tests/InstancingTest.cpp
+++ b/src/tests/gl_tests/InstancingTest.cpp
@@ -115,7 +115,7 @@
 
         // TODO: Fix these.  http://anglebug.com/3129
         ANGLE_SKIP_TEST_IF(IsD3D9() && draw == Indexed && geometry == Point);
-        ANGLE_SKIP_TEST_IF(IsD3D9() && IsAMD() && geometry == Point);
+        ANGLE_SKIP_TEST_IF(IsD3D9() && IsAMD());
 
         // D3D11 FL9_3 has a special codepath that emulates instanced points rendering
         // but it has bugs and was only implemented for vertex positions in a buffer object,
diff --git a/src/tests/gl_tests/ProgramBinaryTest.cpp b/src/tests/gl_tests/ProgramBinaryTest.cpp
index 0a94814..006b8ca 100644
--- a/src/tests/gl_tests/ProgramBinaryTest.cpp
+++ b/src/tests/gl_tests/ProgramBinaryTest.cpp
@@ -28,6 +28,9 @@
         setConfigGreenBits(8);
         setConfigBlueBits(8);
         setConfigAlphaBits(8);
+
+        // Test flakiness was noticed when reusing displays.
+        forceNewDisplay();
     }
 
     void SetUp() override
@@ -52,7 +55,6 @@
     {
         glDeleteProgram(mProgram);
         glDeleteBuffers(1, &mBuffer);
-
         ANGLETest::TearDown();
     }
 
@@ -259,6 +261,12 @@
 class ProgramBinaryES3Test : public ANGLETest
 {
   protected:
+    ProgramBinaryES3Test()
+    {
+        // Test flakiness was noticed when reusing displays.
+        forceNewDisplay();
+    }
+
     void testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst);
 };
 
@@ -368,6 +376,9 @@
         setConfigGreenBits(8);
         setConfigBlueBits(8);
         setConfigAlphaBits(8);
+
+        // Test flakiness was noticed when reusing displays.
+        forceNewDisplay();
     }
 };
 
diff --git a/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp b/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp
index 18b46d3..85b56a7 100644
--- a/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp
+++ b/src/tests/gl_tests/RobustBufferAccessBehaviorTest.cpp
@@ -29,6 +29,9 @@
         setConfigGreenBits(8);
         setConfigBlueBits(8);
         setConfigAlphaBits(8);
+
+        // Test flakiness was noticed when reusing displays.
+        forceNewDisplay();
     }
 
     void TearDown() override
diff --git a/src/tests/gl_tests/RobustResourceInitTest.cpp b/src/tests/gl_tests/RobustResourceInitTest.cpp
index a5c5002..46f28ee 100644
--- a/src/tests/gl_tests/RobustResourceInitTest.cpp
+++ b/src/tests/gl_tests/RobustResourceInitTest.cpp
@@ -204,6 +204,9 @@
         setConfigStencilBits(8);
 
         setRobustResourceInit(true);
+
+        // Test flakiness was noticed when reusing displays.
+        forceNewDisplay();
     }
 
     bool hasGLExtension() { return extensionEnabled("GL_ANGLE_robust_resource_initialization"); }
diff --git a/src/tests/gl_tests/ShaderStorageBufferTest.cpp b/src/tests/gl_tests/ShaderStorageBufferTest.cpp
index d23e782..23c81c0 100644
--- a/src/tests/gl_tests/ShaderStorageBufferTest.cpp
+++ b/src/tests/gl_tests/ShaderStorageBufferTest.cpp
@@ -65,6 +65,9 @@
         setConfigGreenBits(8);
         setConfigBlueBits(8);
         setConfigAlphaBits(8);
+
+        // Test flakiness was noticed when reusing displays.
+        forceNewDisplay();
     }
 
     void runMatrixTest(const MatrixCase &matrixCase)
@@ -1590,6 +1593,9 @@
     // http://anglebug.com/1951
     ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux());
 
+    // Seems to fail on Windows NVIDIA GL when tests are run without interruption.
+    ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsOpenGL());
+
     constexpr char kComputeShaderSource[] = R"(#version 310 es
 layout (local_size_x=1) in;
 layout(binding=0, std140) buffer Storage0
diff --git a/src/tests/gl_tests/TextureRectangleTest.cpp b/src/tests/gl_tests/TextureRectangleTest.cpp
index d0b998c..592a7db 100644
--- a/src/tests/gl_tests/TextureRectangleTest.cpp
+++ b/src/tests/gl_tests/TextureRectangleTest.cpp
@@ -68,7 +68,7 @@
 
     // Defining a texture of the max size is allowed
     {
-        ScopedIgnorePlatformMessages ignore(this);
+        ScopedIgnorePlatformMessages ignore;
 
         glTexImage2D(GL_TEXTURE_RECTANGLE_ANGLE, 0, GL_RGBA, maxSize, maxSize, 0, GL_RGBA,
                      GL_UNSIGNED_BYTE, nullptr);
@@ -154,7 +154,7 @@
 
     // Defining a texture of the max size is allowed but still allow for OOM
     {
-        ScopedIgnorePlatformMessages ignore(this);
+        ScopedIgnorePlatformMessages ignore;
 
         GLTexture tex;
         glBindTexture(GL_TEXTURE_RECTANGLE_ANGLE, tex);
diff --git a/src/tests/test_utils/ANGLETest.cpp b/src/tests/test_utils/ANGLETest.cpp
index 41c35ee..f34754e 100644
--- a/src/tests/test_utils/ANGLETest.cpp
+++ b/src/tests/test_utils/ANGLETest.cpp
@@ -14,10 +14,6 @@
 #include "util/EGLWindow.h"
 #include "util/OSWindow.h"
 
-#if defined(ANGLE_USE_UTIL_LOADER) && defined(ANGLE_PLATFORM_WINDOWS)
-#    include "util/windows/WGLWindow.h"
-#endif  // defined(ANGLE_USE_UTIL_LOADER) && defined(ANGLE_PLATFORM_WINDOWS)
-
 #if defined(ANGLE_PLATFORM_WINDOWS)
 #    include <VersionHelpers.h>
 #endif  // defined(ANGLE_PLATFORM_WINDOWS)
@@ -172,6 +168,15 @@
 
     return nullptr;
 }
+
+bool ShouldAlwaysForceNewDisplay()
+{
+    // We prefer to reuse config displays. This is faster and solves a driver issue where creating
+    // many displays causes crashes. However this exposes other driver bugs on many other platforms.
+    // Conservatively enable the feature only on Windows Intel and NVIDIA for now.
+    SystemInfo *systemInfo = GetTestSystemInfo();
+    return (!systemInfo || !IsWindows() || systemInfo->hasAMDGPU());
+}
 }  // anonymous namespace
 
 GLColorRGB::GLColorRGB() : R(0), G(0), B(0) {}
@@ -278,9 +283,17 @@
     EXPECT_GL_NO_ERROR();
     return actual;
 }
-
 }  // namespace angle
 
+namespace
+{
+angle::PlatformMethods gDefaultPlatformMethods;
+TestPlatformContext gPlatformContext;
+
+// After a fixed number of iterations we reset the test window. This works around some driver bugs.
+constexpr uint32_t kWindowReuseLimit = 50;
+}  // anonymous namespace
+
 // static
 std::array<angle::Vector3, 6> ANGLETestBase::GetQuadVertices()
 {
@@ -300,45 +313,62 @@
 }
 
 ANGLETestBase::ANGLETestBase(const angle::PlatformParameters &params)
-    : mEGLWindow(nullptr),
-      mWGLWindow(nullptr),
-      mWidth(16),
+    : mWidth(16),
       mHeight(16),
       mIgnoreD3D11SDKLayersWarnings(false),
       mQuadVertexBuffer(0),
       mQuadIndexBuffer(0),
       m2DTexturedQuadProgram(0),
       m3DTexturedQuadProgram(0),
-      mDeferContextInit(false)
+      mDeferContextInit(false),
+      mAlwaysForceNewDisplay(angle::ShouldAlwaysForceNewDisplay()),
+      mForceNewDisplay(mAlwaysForceNewDisplay),
+      mCurrentPlatform(nullptr)
 {
+    auto iter = gPlatforms.find(params);
+    if (iter != gPlatforms.end())
+    {
+        mCurrentPlatform = &iter->second;
+        mCurrentPlatform->configParams.reset();
+
+        // Default debug layers to enabled in tests.
+        mCurrentPlatform->configParams.debugLayersEnabled = true;
+        return;
+    }
+
+    Platform platform;
+    auto insertIter  = gPlatforms.emplace(params, platform);
+    mCurrentPlatform = &insertIter.first->second;
+
+    std::stringstream windowNameStream;
+    windowNameStream << "ANGLE Tests - " << params;
+    std::string windowName = windowNameStream.str();
+
+    if (mAlwaysForceNewDisplay)
+    {
+        mCurrentPlatform->osWindow = mOSWindowSingleton;
+    }
+
+    if (!mCurrentPlatform->osWindow)
+    {
+        mCurrentPlatform->osWindow = OSWindow::New();
+        if (!mCurrentPlatform->osWindow->initialize(windowName.c_str(), 128, 128))
+        {
+            std::cerr << "Failed to initialize OS Window.";
+        }
+
+        mOSWindowSingleton = mCurrentPlatform->osWindow;
+    }
+
+    // On Linux we must keep the test windows visible. On Windows it doesn't seem to need it.
+    mCurrentPlatform->osWindow->setVisible(!angle::IsWindows());
+
     switch (params.driver)
     {
         case angle::GLESDriverType::AngleEGL:
         {
-            mEGLWindow =
+            mCurrentPlatform->eglWindow =
                 EGLWindow::New(params.majorVersion, params.minorVersion, params.eglParameters);
-
-            // Default debug layers to enabled in tests.
-            mConfigParameters.debugLayersEnabled = true;
-
-            // Workaround for NVIDIA not being able to share OpenGL and Vulkan contexts.
-            // Workaround if any of the GPUs is Nvidia, since we can't detect current GPU.
-            EGLint renderer = params.getRenderer();
-            bool needsWindowSwap =
-                hasNVIDIAGPU() && mLastRendererType.valid() &&
-                ((renderer != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE) !=
-                 (mLastRendererType.value() != EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE));
-
-            if (needsWindowSwap)
-            {
-                DestroyTestWindow();
-                if (!InitTestWindow())
-                {
-                    std::cerr << "Failed to create ANGLE test window.";
-                }
-            }
-
-            mLastRendererType = renderer;
             break;
         }
 
@@ -350,14 +380,14 @@
 
         case angle::GLESDriverType::SystemWGL:
         {
-#if defined(ANGLE_USE_UTIL_LOADER) && defined(ANGLE_PLATFORM_WINDOWS)
-            mWGLWindow = WGLWindow::New(params.majorVersion, params.minorVersion);
-#else
+            // WGL tests are currently disabled.
             std::cerr << "Unsupported driver." << std::endl;
-#endif  // defined(ANGLE_USE_UTIL_LOADER) && defined(ANGLE_PLATFORM_WINDOWS)
             break;
         }
     }
+
+    // Default debug layers to enabled in tests.
+    mCurrentPlatform->configParams.debugLayersEnabled = true;
 }
 
 ANGLETestBase::~ANGLETestBase()
@@ -378,81 +408,63 @@
     {
         glDeleteProgram(m3DTexturedQuadProgram);
     }
-    EGLWindow::Delete(&mEGLWindow);
-
-#if defined(ANGLE_USE_UTIL_LOADER) && defined(ANGLE_PLATFORM_WINDOWS)
-    WGLWindow::Delete(&mWGLWindow);
-#endif  // defined(ANGLE_USE_UTIL_LOADER) && defined(ANGLE_PLATFORM_WINDOWS)
 }
 
 void ANGLETestBase::ANGLETestSetUp()
 {
-    mPlatformContext.ignoreMessages   = false;
-    mPlatformContext.warningsAsErrors = false;
-    mPlatformContext.currentTest      = this;
+    gDefaultPlatformMethods.overrideWorkaroundsD3D = angle::TestPlatform_overrideWorkaroundsD3D;
+    gDefaultPlatformMethods.overrideFeaturesVk     = angle::TestPlatform_overrideFeaturesVk;
+    gDefaultPlatformMethods.logError               = angle::TestPlatform_logError;
+    gDefaultPlatformMethods.logWarning             = angle::TestPlatform_logWarning;
+    gDefaultPlatformMethods.logInfo                = angle::TestPlatform_logInfo;
+    gDefaultPlatformMethods.context                = &gPlatformContext;
+    mCurrentPlatform->configParams.platformMethods = &gDefaultPlatformMethods;
+
+    gPlatformContext.ignoreMessages   = false;
+    gPlatformContext.warningsAsErrors = false;
+    gPlatformContext.currentTest      = this;
 
     // Resize the window before creating the context so that the first make current
     // sets the viewport and scissor box to the right size.
     bool needSwap = false;
-    if (mOSWindow->getWidth() != mWidth || mOSWindow->getHeight() != mHeight)
+    if (mCurrentPlatform->osWindow->getWidth() != mWidth ||
+        mCurrentPlatform->osWindow->getHeight() != mHeight)
     {
-        if (!mOSWindow->resize(mWidth, mHeight))
+        if (!mCurrentPlatform->osWindow->resize(mWidth, mHeight))
         {
             FAIL() << "Failed to resize ANGLE test window.";
         }
         needSwap = true;
     }
 
-    if (mWGLWindow)
+    // WGL tests are currently disabled.
+    if (mCurrentPlatform->wglWindow)
     {
-#if defined(ANGLE_PLATFORM_WINDOWS) && defined(ANGLE_USE_UTIL_LOADER)
-        if (!mWGLWindow->initializeGL(mOSWindow, ANGLETestEnvironment::GetWGLLibrary(),
-                                      mConfigParameters))
-        {
-            std::cerr << "WGL init failed.. trying again with new OSWindow." << std::endl;
-
-            // Retry once with a fresh OSWindow. This is necessary to work around a bug in the
-            // NVIDIA WGL implementation. It seems sometimes the pixel format gets stuck. Using
-            // a new windows seems to allow us to set the new pixel format correctly.
-            DestroyTestWindow();
-            if (!InitTestWindow())
-            {
-                FAIL() << "Failed to create ANGLE test window.";
-            }
-
-            if (!mWGLWindow->initializeGL(mOSWindow, ANGLETestEnvironment::GetWGLLibrary(),
-                                          mConfigParameters))
-            {
-                FAIL() << "WGL init failed.";
-            }
-        }
-#else
         FAIL() << "Unsupported driver.";
-#endif  // defined(ANGLE_PLATFORM_WINDOWS) && defined(ANGLE_USE_UTIL_LOADER)
     }
     else
     {
-        mPlatformMethods.overrideWorkaroundsD3D = angle::TestPlatform_overrideWorkaroundsD3D;
-        mPlatformMethods.overrideFeaturesVk     = angle::TestPlatform_overrideFeaturesVk;
-        mPlatformMethods.logError               = angle::TestPlatform_logError;
-        mPlatformMethods.logWarning             = angle::TestPlatform_logWarning;
-        mPlatformMethods.logInfo                = angle::TestPlatform_logInfo;
-        mPlatformMethods.context                = &mPlatformContext;
-        mConfigParameters.platformMethods       = &mPlatformMethods;
-
-        if (!mEGLWindow->initializeDisplay(mOSWindow, ANGLETestEnvironment::GetEGLLibrary(),
-                                           mConfigParameters))
+        if (mForceNewDisplay || !mCurrentPlatform->eglWindow->isDisplayInitialized() ||
+            !ConfigParameters::CanShareDisplay(mCurrentPlatform->configParams,
+                                               mCurrentPlatform->eglWindow->getConfigParams()))
         {
-            FAIL() << "egl display init failed.";
+            mCurrentPlatform->eglWindow->destroyGL();
+            if (!mCurrentPlatform->eglWindow->initializeDisplay(
+                    mCurrentPlatform->osWindow, ANGLETestEnvironment::GetEGLLibrary(),
+                    mCurrentPlatform->configParams))
+            {
+                FAIL() << "egl display init failed.";
+            }
         }
 
-        if (!mEGLWindow->initializeSurface(mOSWindow, ANGLETestEnvironment::GetEGLLibrary(),
-                                           mConfigParameters))
+        if (!mCurrentPlatform->eglWindow->initializeSurface(mCurrentPlatform->osWindow,
+                                                            ANGLETestEnvironment::GetEGLLibrary(),
+                                                            mCurrentPlatform->configParams))
         {
             FAIL() << "egl surface init failed.";
         }
 
-        if (!mDeferContextInit && !mEGLWindow->initializeContext())
+        if (!mDeferContextInit && !mCurrentPlatform->eglWindow->initializeContext())
         {
             FAIL() << "GL Context init failed.";
         }
@@ -477,26 +489,33 @@
 
 void ANGLETestBase::ANGLETestTearDown()
 {
-    if (mEGLWindow)
-    {
-        mConfigParameters.platformMethods = nullptr;
-        checkD3D11SDKLayersMessages();
-    }
+    gPlatformContext.currentTest = nullptr;
 
-    mPlatformContext.currentTest = nullptr;
-
-    const auto &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());
 
     swapBuffers();
+    mCurrentPlatform->osWindow->messageLoop();
 
-    mOSWindow->messageLoop();
+    if (mCurrentPlatform->eglWindow)
+    {
+        checkD3D11SDKLayersMessages();
+    }
 
-    getGLWindow()->destroyGL();
+    if (mCurrentPlatform->reuseCounter++ >= kWindowReuseLimit || mForceNewDisplay)
+    {
+        mCurrentPlatform->reuseCounter = 0;
+        getGLWindow()->destroyGL();
+    }
+    else
+    {
+        mCurrentPlatform->eglWindow->destroyContext();
+        mCurrentPlatform->eglWindow->destroySurface();
+    }
 
     // Check for quit message
     Event myEvent;
-    while (mOSWindow->popEvent(&myEvent))
+    while (mCurrentPlatform->osWindow->popEvent(&myEvent))
     {
         if (myEvent.Type == Event::EVENT_CLOSED)
         {
@@ -511,7 +530,7 @@
     {
         getGLWindow()->swap();
 
-        if (mEGLWindow)
+        if (mCurrentPlatform->eglWindow)
         {
             EXPECT_EGL_SUCCESS();
         }
@@ -863,14 +882,15 @@
     // On Windows D3D11, check ID3D11InfoQueue to see if any D3D11 SDK Layers messages
     // were outputted by the test. We enable the Debug layers in Release tests as well.
     if (mIgnoreD3D11SDKLayersWarnings ||
-        mEGLWindow->getPlatform().renderer != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE ||
-        mEGLWindow->getDisplay() == EGL_NO_DISPLAY)
+        mCurrentPlatform->eglWindow->getPlatform().renderer !=
+            EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE ||
+        mCurrentPlatform->eglWindow->getDisplay() == EGL_NO_DISPLAY)
     {
         return;
     }
 
-    const char *extensionString =
-        static_cast<const char *>(eglQueryString(mEGLWindow->getDisplay(), EGL_EXTENSIONS));
+    const char *extensionString = static_cast<const char *>(
+        eglQueryString(mCurrentPlatform->eglWindow->getDisplay(), EGL_EXTENSIONS));
     if (!extensionString)
     {
         std::cout << "Error getting extension string from EGL Window." << std::endl;
@@ -895,7 +915,8 @@
     ASSERT_NE(nullptr, queryDisplayAttribEXT);
     ASSERT_NE(nullptr, queryDeviceAttribEXT);
 
-    ASSERT_EGL_TRUE(queryDisplayAttribEXT(mEGLWindow->getDisplay(), EGL_DEVICE_EXT, &angleDevice));
+    ASSERT_EGL_TRUE(queryDisplayAttribEXT(mCurrentPlatform->eglWindow->getDisplay(), EGL_DEVICE_EXT,
+                                          &angleDevice));
     ASSERT_EGL_TRUE(queryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice),
                                          EGL_D3D11_DEVICE_ANGLE, &device));
     ID3D11Device *d3d11Device = reinterpret_cast<ID3D11Device *>(device);
@@ -936,12 +957,6 @@
 #endif  // defined(ANGLE_PLATFORM_WINDOWS)
 }
 
-bool ANGLETestBase::hasNVIDIAGPU() const
-{
-    angle::SystemInfo *systemInfo = angle::GetTestSystemInfo();
-    return systemInfo && systemInfo->hasNVIDIAGPU();
-}
-
 bool ANGLETestBase::extensionEnabled(const std::string &extName)
 {
     return CheckExtensionExists(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)),
@@ -994,107 +1009,116 @@
 
 GLWindowBase *ANGLETestBase::getGLWindow() const
 {
-    return mWGLWindow ? reinterpret_cast<GLWindowBase *>(mWGLWindow) : mEGLWindow;
+    // WGL tests are currently disabled.
+    assert(!mCurrentPlatform->wglWindow);
+    return mCurrentPlatform->eglWindow;
 }
 
 void ANGLETestBase::setConfigRedBits(int bits)
 {
-    mConfigParameters.redBits = bits;
+    mCurrentPlatform->configParams.redBits = bits;
 }
 
 void ANGLETestBase::setConfigGreenBits(int bits)
 {
-    mConfigParameters.greenBits = bits;
+    mCurrentPlatform->configParams.greenBits = bits;
 }
 
 void ANGLETestBase::setConfigBlueBits(int bits)
 {
-    mConfigParameters.blueBits = bits;
+    mCurrentPlatform->configParams.blueBits = bits;
 }
 
 void ANGLETestBase::setConfigAlphaBits(int bits)
 {
-    mConfigParameters.alphaBits = bits;
+    mCurrentPlatform->configParams.alphaBits = bits;
 }
 
 void ANGLETestBase::setConfigDepthBits(int bits)
 {
-    mConfigParameters.depthBits = bits;
+    mCurrentPlatform->configParams.depthBits = bits;
 }
 
 void ANGLETestBase::setConfigStencilBits(int bits)
 {
-    mConfigParameters.stencilBits = bits;
+    mCurrentPlatform->configParams.stencilBits = bits;
 }
 
 void ANGLETestBase::setConfigComponentType(EGLenum componentType)
 {
-    mConfigParameters.componentType = componentType;
+    mCurrentPlatform->configParams.componentType = componentType;
 }
 
 void ANGLETestBase::setMultisampleEnabled(bool enabled)
 {
-    mConfigParameters.multisample = enabled;
+    mCurrentPlatform->configParams.multisample = enabled;
 }
 
 void ANGLETestBase::setSamples(EGLint samples)
 {
-    mConfigParameters.samples = samples;
+    mCurrentPlatform->configParams.samples = samples;
 }
 
 void ANGLETestBase::setDebugEnabled(bool enabled)
 {
-    mConfigParameters.debug = enabled;
+    mCurrentPlatform->configParams.debug = enabled;
 }
 
 void ANGLETestBase::setNoErrorEnabled(bool enabled)
 {
-    mConfigParameters.noError = enabled;
+    mCurrentPlatform->configParams.noError = enabled;
 }
 
 void ANGLETestBase::setWebGLCompatibilityEnabled(bool webglCompatibility)
 {
-    mConfigParameters.webGLCompatibility = webglCompatibility;
+    mCurrentPlatform->configParams.webGLCompatibility = webglCompatibility;
 }
 
 void ANGLETestBase::setExtensionsEnabled(bool extensionsEnabled)
 {
-    mConfigParameters.extensionsEnabled = extensionsEnabled;
+    mCurrentPlatform->configParams.extensionsEnabled = extensionsEnabled;
 }
 
 void ANGLETestBase::setRobustAccess(bool enabled)
 {
-    mConfigParameters.robustAccess = enabled;
+    mCurrentPlatform->configParams.robustAccess = enabled;
 }
 
 void ANGLETestBase::setBindGeneratesResource(bool bindGeneratesResource)
 {
-    mConfigParameters.bindGeneratesResource = bindGeneratesResource;
+    mCurrentPlatform->configParams.bindGeneratesResource = bindGeneratesResource;
 }
 
 void ANGLETestBase::setDebugLayersEnabled(bool enabled)
 {
-    mConfigParameters.debugLayersEnabled = enabled;
+    mCurrentPlatform->configParams.debugLayersEnabled = enabled;
 }
 
 void ANGLETestBase::setClientArraysEnabled(bool enabled)
 {
-    mConfigParameters.clientArraysEnabled = enabled;
+    mCurrentPlatform->configParams.clientArraysEnabled = enabled;
 }
 
 void ANGLETestBase::setRobustResourceInit(bool enabled)
 {
-    mConfigParameters.robustResourceInit = enabled;
+    mCurrentPlatform->configParams.robustResourceInit = enabled;
 }
 
-void ANGLETestBase::setContextProgramCacheEnabled(bool enabled)
+void ANGLETestBase::setContextProgramCacheEnabled(bool enabled,
+                                                  angle::CacheProgramFunc cacheProgramFunc)
 {
-    mConfigParameters.contextProgramCacheEnabled = enabled;
+    mCurrentPlatform->configParams.contextProgramCacheEnabled = enabled;
+    gDefaultPlatformMethods.cacheProgram                      = cacheProgramFunc;
 }
 
 void ANGLETestBase::setContextVirtualization(bool enabled)
 {
-    mConfigParameters.contextVirtualization = enabled;
+    mCurrentPlatform->configParams.contextVirtualization = enabled;
+}
+
+void ANGLETestBase::forceNewDisplay()
+{
+    mForceNewDisplay = true;
 }
 
 void ANGLETestBase::setDeferContextInit(bool enabled)
@@ -1114,7 +1138,7 @@
 
 EGLWindow *ANGLETestBase::getEGLWindow() const
 {
-    return mEGLWindow;
+    return mCurrentPlatform->eglWindow;
 }
 
 int ANGLETestBase::getWindowWidth() const
@@ -1129,38 +1153,12 @@
 
 bool ANGLETestBase::isMultisampleEnabled() const
 {
-    return mEGLWindow->isMultisample();
+    return mCurrentPlatform->eglWindow->isMultisample();
 }
 
-// static
-bool ANGLETestBase::InitTestWindow()
+void ANGLETestBase::setWindowVisible(bool isVisible)
 {
-    mOSWindow = OSWindow::New();
-    if (!mOSWindow->initialize("ANGLE_TEST", 128, 128))
-    {
-        return false;
-    }
-
-    mOSWindow->setVisible(true);
-
-    return true;
-}
-
-// static
-bool ANGLETestBase::DestroyTestWindow()
-{
-    if (mOSWindow)
-    {
-        mOSWindow->destroy();
-        OSWindow::Delete(&mOSWindow);
-    }
-
-    return true;
-}
-
-void ANGLETestBase::SetWindowVisible(bool isVisible)
-{
-    mOSWindow->setVisible(isVisible);
+    mCurrentPlatform->osWindow->setVisible(isVisible);
 }
 
 bool IsIntel()
@@ -1256,10 +1254,13 @@
     return !IsDebug();
 }
 
+ANGLETestBase::Platform::Platform()  = default;
+ANGLETestBase::Platform::~Platform() = default;
+
 EGLint ANGLETestBase::getPlatformRenderer() const
 {
-    assert(mEGLWindow);
-    return mEGLWindow->getPlatform().renderer;
+    assert(mCurrentPlatform->eglWindow);
+    return mCurrentPlatform->eglWindow->getPlatform().renderer;
 }
 
 void ANGLETestBase::ignoreD3D11SDKLayersWarnings()
@@ -1273,39 +1274,30 @@
 #if defined(ANGLE_PLATFORM_WINDOWS)
     // Only do warnings-as-errors on 8 and above. We may fall back to the old
     // compiler DLL on Windows 7.
-    mPlatformContext.warningsAsErrors = IsWindows8OrGreater();
+    gPlatformContext.warningsAsErrors = IsWindows8OrGreater();
 #endif  // defined(ANGLE_PLATFORM_WINDOWS)
 }
 
-ANGLETestBase::ScopedIgnorePlatformMessages::ScopedIgnorePlatformMessages(ANGLETestBase *test)
-    : mTest(test)
+ANGLETestBase::ScopedIgnorePlatformMessages::ScopedIgnorePlatformMessages()
 {
-    mTest->mPlatformContext.ignoreMessages = true;
+    gPlatformContext.ignoreMessages = true;
 }
 
 ANGLETestBase::ScopedIgnorePlatformMessages::~ScopedIgnorePlatformMessages()
 {
-    mTest->mPlatformContext.ignoreMessages = false;
+    gPlatformContext.ignoreMessages = false;
 }
 
-OSWindow *ANGLETestBase::mOSWindow = nullptr;
+OSWindow *ANGLETestBase::mOSWindowSingleton = nullptr;
+std::map<angle::PlatformParameters, ANGLETestBase::Platform> ANGLETestBase::gPlatforms;
 Optional<EGLint> ANGLETestBase::mLastRendererType;
 
 std::unique_ptr<angle::Library> ANGLETestEnvironment::gEGLLibrary;
 std::unique_ptr<angle::Library> ANGLETestEnvironment::gWGLLibrary;
 
-void ANGLETestEnvironment::SetUp()
-{
-    if (!ANGLETestBase::InitTestWindow())
-    {
-        FAIL() << "Failed to create ANGLE test window.";
-    }
-}
+void ANGLETestEnvironment::SetUp() {}
 
-void ANGLETestEnvironment::TearDown()
-{
-    ANGLETestBase::DestroyTestWindow();
-}
+void ANGLETestEnvironment::TearDown() {}
 
 angle::Library *ANGLETestEnvironment::GetEGLLibrary()
 {
diff --git a/src/tests/test_utils/ANGLETest.h b/src/tests/test_utils/ANGLETest.h
index e3ea71b..361d4f2 100644
--- a/src/tests/test_utils/ANGLETest.h
+++ b/src/tests/test_utils/ANGLETest.h
@@ -262,9 +262,7 @@
     virtual ~ANGLETestBase();
 
   public:
-    static bool InitTestWindow();
-    static bool DestroyTestWindow();
-    static void SetWindowVisible(bool isVisible);
+    void setWindowVisible(bool isVisible);
     static bool eglDisplayExtensionEnabled(EGLDisplay display, const std::string &extName);
 
     virtual void overrideWorkaroundsD3D(angle::WorkaroundsD3D *workaroundsD3D) {}
@@ -357,8 +355,9 @@
     void setDebugLayersEnabled(bool enabled);
     void setClientArraysEnabled(bool enabled);
     void setRobustResourceInit(bool enabled);
-    void setContextProgramCacheEnabled(bool enabled);
+    void setContextProgramCacheEnabled(bool enabled, angle::CacheProgramFunc cacheProgramFunc);
     void setContextVirtualization(bool enabled);
+    void forceNewDisplay();
 
     // Some EGL extension tests would like to defer the Context init until the test body.
     void setDeferContextInit(bool enabled);
@@ -379,28 +378,22 @@
     // Allows a test to be more restrictive about platform warnings.
     void treatPlatformWarningsAsErrors();
 
-    static OSWindow *GetOSWindow() { return mOSWindow; }
+    OSWindow *getOSWindow() { return mCurrentPlatform->osWindow; }
 
     GLuint get2DTexturedQuadProgram();
 
     // Has a float uniform "u_layer" to choose the 3D texture layer.
     GLuint get3DTexturedQuadProgram();
 
-    angle::PlatformMethods mPlatformMethods;
-
     class ScopedIgnorePlatformMessages : angle::NonCopyable
     {
       public:
-        ScopedIgnorePlatformMessages(ANGLETestBase *test);
+        ScopedIgnorePlatformMessages();
         ~ScopedIgnorePlatformMessages();
-
-      private:
-        ANGLETestBase *mTest;
     };
 
   private:
     void checkD3D11SDKLayersMessages();
-    bool hasNVIDIAGPU() const;
 
     void drawQuad(GLuint program,
                   const std::string &positionAttribName,
@@ -410,9 +403,18 @@
                   bool useInstancedDrawCalls,
                   GLuint numInstances);
 
-    EGLWindow *mEGLWindow;
-    WGLWindow *mWGLWindow;
-    ConfigParameters mConfigParameters;
+    struct Platform
+    {
+        Platform();
+        ~Platform();
+
+        EGLWindow *eglWindow = nullptr;
+        WGLWindow *wglWindow = nullptr;
+        OSWindow *osWindow   = nullptr;
+        ConfigParameters configParams;
+        uint32_t reuseCounter = 0;
+    };
+
     int mWidth;
     int mHeight;
 
@@ -426,11 +428,17 @@
     GLuint m2DTexturedQuadProgram;
     GLuint m3DTexturedQuadProgram;
 
-    TestPlatformContext mPlatformContext;
-
     bool mDeferContextInit;
+    bool mAlwaysForceNewDisplay;
+    bool mForceNewDisplay;
 
-    static OSWindow *mOSWindow;
+    // On most systems we force a new display on every test instance. For these configs we can
+    // share a single OSWindow instance. With display reuse we need a separate OSWindow for each
+    // different config. This OSWindow sharing seemed to lead to driver bugs on some platforms.
+    static OSWindow *mOSWindowSingleton;
+
+    static std::map<angle::PlatformParameters, Platform> gPlatforms;
+    Platform *mCurrentPlatform;
 
     // Workaround for NVIDIA not being able to share a window with OpenGL and Vulkan.
     static Optional<EGLint> mLastRendererType;
diff --git a/util/EGLWindow.cpp b/util/EGLWindow.cpp
index e066bfb..457de29 100644
--- a/util/EGLWindow.cpp
+++ b/util/EGLWindow.cpp
@@ -114,6 +114,14 @@
     *this = ConfigParameters();
 }
 
+// static
+bool ConfigParameters::CanShareDisplay(const ConfigParameters &a, const ConfigParameters &b)
+{
+    return a.debugLayersEnabled == b.debugLayersEnabled &&
+           a.contextVirtualization == b.contextVirtualization &&
+           a.platformMethods == b.platformMethods;
+}
+
 // GLWindowBase implementation.
 GLWindowBase::GLWindowBase(EGLint glesMajorVersion, EGLint glesMinorVersion)
     : mClientMajorVersion(glesMajorVersion), mClientMinorVersion(glesMinorVersion)
diff --git a/util/EGLWindow.h b/util/EGLWindow.h
index 256290a..97fbdb7 100644
--- a/util/EGLWindow.h
+++ b/util/EGLWindow.h
@@ -33,6 +33,8 @@
 
     void reset();
 
+    static bool CanShareDisplay(const ConfigParameters &a, const ConfigParameters &b);
+
     // Display parameters.
     Optional<bool> debugLayersEnabled;
     Optional<bool> contextVirtualization;
diff --git a/util/windows/win32/Win32Window.cpp b/util/windows/win32/Win32Window.cpp
index 7d51457..c7317cb 100644
--- a/util/windows/win32/Win32Window.cpp
+++ b/util/windows/win32/Win32Window.cpp
@@ -550,7 +550,7 @@
     }
 
     DWORD parentStyle = WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU;
-    DWORD parentExtendedStyle = WS_EX_APPWINDOW;
+    DWORD parentExtendedStyle = WS_EX_APPWINDOW | WS_EX_TOOLWINDOW;
 
     RECT sizeRect = {0, 0, static_cast<LONG>(width), static_cast<LONG>(height)};
     AdjustWindowRectEx(&sizeRect, parentStyle, FALSE, parentExtendedStyle);