• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 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 
7 // EGLRobustnessTest.cpp: tests for EGL_EXT_create_context_robustness
8 //
9 // Tests causing GPU resets are disabled, use the following args to run them:
10 // --gtest_also_run_disabled_tests --gtest_filter=EGLRobustnessTest\*
11 
12 #include <gtest/gtest.h>
13 
14 #include "test_utils/ANGLETest.h"
15 #include "util/OSWindow.h"
16 
17 using namespace angle;
18 
19 class EGLRobustnessTest : public ANGLETest
20 {
21   public:
testSetUp()22     void testSetUp() override
23     {
24         mOSWindow = OSWindow::New();
25         mOSWindow->initialize("EGLRobustnessTest", 500, 500);
26         setWindowVisible(mOSWindow, true);
27 
28         const auto &platform = GetParam().eglParameters;
29 
30         std::vector<EGLint> displayAttributes;
31         displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
32         displayAttributes.push_back(platform.renderer);
33         displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE);
34         displayAttributes.push_back(platform.majorVersion);
35         displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE);
36         displayAttributes.push_back(platform.minorVersion);
37 
38         if (platform.deviceType != EGL_DONT_CARE)
39         {
40             displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
41             displayAttributes.push_back(platform.deviceType);
42         }
43 
44         displayAttributes.push_back(EGL_NONE);
45 
46         mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
47                                             reinterpret_cast<void *>(mOSWindow->getNativeDisplay()),
48                                             &displayAttributes[0]);
49         ASSERT_NE(EGL_NO_DISPLAY, mDisplay);
50 
51         ASSERT_TRUE(eglInitialize(mDisplay, nullptr, nullptr) == EGL_TRUE);
52 
53         const char *extensions = eglQueryString(mDisplay, EGL_EXTENSIONS);
54         if (strstr(extensions, "EGL_EXT_create_context_robustness") == nullptr)
55         {
56             std::cout << "Test skipped due to missing EGL_EXT_create_context_robustness"
57                       << std::endl;
58             return;
59         }
60 
61         int nConfigs = 0;
62         ASSERT_TRUE(eglGetConfigs(mDisplay, nullptr, 0, &nConfigs) == EGL_TRUE);
63         ASSERT_LE(1, nConfigs);
64 
65         std::vector<EGLConfig> allConfigs(nConfigs);
66         int nReturnedConfigs = 0;
67         ASSERT_TRUE(eglGetConfigs(mDisplay, allConfigs.data(), nConfigs, &nReturnedConfigs) ==
68                     EGL_TRUE);
69         ASSERT_EQ(nConfigs, nReturnedConfigs);
70 
71         for (const EGLConfig &config : allConfigs)
72         {
73             EGLint surfaceType;
74             eglGetConfigAttrib(mDisplay, config, EGL_SURFACE_TYPE, &surfaceType);
75 
76             if ((surfaceType & EGL_WINDOW_BIT) != 0)
77             {
78                 mConfig      = config;
79                 mInitialized = true;
80                 break;
81             }
82         }
83 
84         if (mInitialized)
85         {
86             mWindow =
87                 eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr);
88             ASSERT_EGL_SUCCESS();
89         }
90     }
91 
testTearDown()92     void testTearDown() override
93     {
94         eglDestroySurface(mDisplay, mWindow);
95         eglDestroyContext(mDisplay, mContext);
96         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
97         eglTerminate(mDisplay);
98         EXPECT_EGL_SUCCESS();
99 
100         OSWindow::Delete(&mOSWindow);
101     }
102 
createContext(EGLint resetStrategy)103     void createContext(EGLint resetStrategy)
104     {
105         const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2,
106                                          EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT,
107                                          resetStrategy, EGL_NONE};
108         mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, contextAttribs);
109         ASSERT_NE(EGL_NO_CONTEXT, mContext);
110 
111         eglMakeCurrent(mDisplay, mWindow, mWindow, mContext);
112         ASSERT_EGL_SUCCESS();
113 
114         const char *extensionString = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
115         ASSERT_NE(nullptr, strstr(extensionString, "GL_ANGLE_instanced_arrays"));
116     }
117 
forceContextReset()118     void forceContextReset()
119     {
120         // Cause a GPU reset by drawing 100,000,000 fullscreen quads
121         GLuint program = CompileProgram(
122             "attribute vec4 pos;\n"
123             "void main() {gl_Position = pos;}\n",
124             "precision mediump float;\n"
125             "void main() {gl_FragColor = vec4(1.0);}\n");
126         ASSERT_NE(0u, program);
127         glUseProgram(program);
128 
129         GLfloat vertices[] = {
130             -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
131             1.0f,  -1.0f, 0.0f, 1.0f, 1.0f,  1.0f, 0.0f, 1.0f,
132         };
133 
134         const int kNumQuads = 10000;
135         std::vector<GLushort> indices(6 * kNumQuads);
136 
137         for (size_t i = 0; i < kNumQuads; i++)
138         {
139             indices[i * 6 + 0] = 0;
140             indices[i * 6 + 1] = 1;
141             indices[i * 6 + 2] = 2;
142             indices[i * 6 + 3] = 1;
143             indices[i * 6 + 4] = 2;
144             indices[i * 6 + 5] = 3;
145         }
146 
147         glBindAttribLocation(program, 0, "pos");
148         glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, vertices);
149         glEnableVertexAttribArray(0);
150 
151         glViewport(0, 0, mOSWindow->getWidth(), mOSWindow->getHeight());
152         glClearColor(1.0, 0.0, 0.0, 1.0);
153         glClear(GL_COLOR_BUFFER_BIT);
154         glDrawElementsInstancedANGLE(GL_TRIANGLES, kNumQuads * 6, GL_UNSIGNED_SHORT, indices.data(),
155                                      10000);
156 
157         glFinish();
158     }
159 
160   protected:
161     EGLDisplay mDisplay = EGL_NO_DISPLAY;
162     EGLSurface mWindow  = EGL_NO_SURFACE;
163     bool mInitialized   = false;
164 
165   private:
166     EGLContext mContext = EGL_NO_CONTEXT;
167     EGLConfig mConfig   = 0;
168     OSWindow *mOSWindow = nullptr;
169 };
170 
171 // Check glGetGraphicsResetStatusEXT returns GL_NO_ERROR if we did nothing
TEST_P(EGLRobustnessTest,NoErrorByDefault)172 TEST_P(EGLRobustnessTest, NoErrorByDefault)
173 {
174     ANGLE_SKIP_TEST_IF(!mInitialized);
175     ASSERT_TRUE(glGetGraphicsResetStatusEXT() == GL_NO_ERROR);
176 }
177 
178 // Checks that the application gets no loss with NO_RESET_NOTIFICATION
TEST_P(EGLRobustnessTest,DISABLED_NoResetNotification)179 TEST_P(EGLRobustnessTest, DISABLED_NoResetNotification)
180 {
181     ANGLE_SKIP_TEST_IF(!mInitialized);
182     createContext(EGL_NO_RESET_NOTIFICATION_EXT);
183 
184     if (!IsWindows())
185     {
186         std::cout << "Test disabled on non Windows platforms because drivers can't recover. "
187                   << "See " << __FILE__ << ":" << __LINE__ << std::endl;
188         return;
189     }
190     std::cout << "Causing a GPU reset, brace for impact." << std::endl;
191 
192     forceContextReset();
193     ASSERT_TRUE(glGetGraphicsResetStatusEXT() == GL_NO_ERROR);
194 }
195 
196 // Checks that resetting the ANGLE display allows to get rid of the context loss.
197 // Also checks that the application gets notified of the loss of the display.
198 // We coalesce both tests to reduce the number of TDRs done on Windows: by default
199 // having more than 5 TDRs in a minute will cause Windows to disable the GPU until
200 // the computer is rebooted.
TEST_P(EGLRobustnessTest,DISABLED_ResettingDisplayWorks)201 TEST_P(EGLRobustnessTest, DISABLED_ResettingDisplayWorks)
202 {
203     // Note that on Windows the OpenGL driver fails hard (popup that closes the application)
204     // on a TDR caused by D3D. Don't run D3D tests at the same time as the OpenGL tests.
205     ANGLE_SKIP_TEST_IF(IsWindows() && isGLRenderer());
206     ANGLE_SKIP_TEST_IF(!mInitialized);
207 
208     createContext(EGL_LOSE_CONTEXT_ON_RESET_EXT);
209 
210     if (!IsWindows())
211     {
212         std::cout << "Test disabled on non Windows platforms because drivers can't recover. "
213                   << "See " << __FILE__ << ":" << __LINE__ << std::endl;
214         return;
215     }
216     std::cout << "Causing a GPU reset, brace for impact." << std::endl;
217 
218     forceContextReset();
219     ASSERT_TRUE(glGetGraphicsResetStatusEXT() != GL_NO_ERROR);
220 
221     recreateTestFixture();
222     ASSERT_TRUE(glGetGraphicsResetStatusEXT() == GL_NO_ERROR);
223 }
224 
225 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EGLRobustnessTest);
226 ANGLE_INSTANTIATE_TEST(EGLRobustnessTest,
227                        WithNoFixture(ES2_VULKAN()),
228                        WithNoFixture(ES2_D3D9()),
229                        WithNoFixture(ES2_D3D11()),
230                        WithNoFixture(ES2_OPENGL()));
231