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 int nReturnedConfigs = 0;
66 ASSERT_TRUE(eglGetConfigs(mDisplay, &mConfig, 1, &nReturnedConfigs) == EGL_TRUE);
67 ASSERT_EQ(1, nReturnedConfigs);
68
69 mWindow = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), nullptr);
70 ASSERT_EGL_SUCCESS();
71
72 mInitialized = true;
73 }
74
testTearDown()75 void testTearDown() override
76 {
77 eglDestroySurface(mDisplay, mWindow);
78 eglDestroyContext(mDisplay, mContext);
79 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
80 eglTerminate(mDisplay);
81 EXPECT_EGL_SUCCESS();
82
83 OSWindow::Delete(&mOSWindow);
84 }
85
createContext(EGLint resetStrategy)86 void createContext(EGLint resetStrategy)
87 {
88 const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2,
89 EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT,
90 resetStrategy, EGL_NONE};
91 mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, contextAttribs);
92 ASSERT_NE(EGL_NO_CONTEXT, mContext);
93
94 eglMakeCurrent(mDisplay, mWindow, mWindow, mContext);
95 ASSERT_EGL_SUCCESS();
96
97 const char *extensionString = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
98 ASSERT_NE(nullptr, strstr(extensionString, "GL_ANGLE_instanced_arrays"));
99 }
100
forceContextReset()101 void forceContextReset()
102 {
103 // Cause a GPU reset by drawing 100,000,000 fullscreen quads
104 GLuint program = CompileProgram(
105 "attribute vec4 pos;\n"
106 "void main() {gl_Position = pos;}\n",
107 "precision mediump float;\n"
108 "void main() {gl_FragColor = vec4(1.0);}\n");
109 ASSERT_NE(0u, program);
110 glUseProgram(program);
111
112 GLfloat vertices[] = {
113 -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f,
114 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
115 };
116
117 const int kNumQuads = 10000;
118 std::vector<GLushort> indices(6 * kNumQuads);
119
120 for (size_t i = 0; i < kNumQuads; i++)
121 {
122 indices[i * 6 + 0] = 0;
123 indices[i * 6 + 1] = 1;
124 indices[i * 6 + 2] = 2;
125 indices[i * 6 + 3] = 1;
126 indices[i * 6 + 4] = 2;
127 indices[i * 6 + 5] = 3;
128 }
129
130 glBindAttribLocation(program, 0, "pos");
131 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, vertices);
132 glEnableVertexAttribArray(0);
133
134 glViewport(0, 0, mOSWindow->getWidth(), mOSWindow->getHeight());
135 glClearColor(1.0, 0.0, 0.0, 1.0);
136 glClear(GL_COLOR_BUFFER_BIT);
137 glDrawElementsInstancedANGLE(GL_TRIANGLES, kNumQuads * 6, GL_UNSIGNED_SHORT, indices.data(),
138 10000);
139
140 glFinish();
141 }
142
143 protected:
144 EGLDisplay mDisplay = EGL_NO_DISPLAY;
145 EGLSurface mWindow = EGL_NO_SURFACE;
146 bool mInitialized = false;
147
148 private:
149 EGLContext mContext = EGL_NO_CONTEXT;
150 EGLConfig mConfig = 0;
151 OSWindow *mOSWindow = nullptr;
152 };
153
154 // Check glGetGraphicsResetStatusEXT returns GL_NO_ERROR if we did nothing
TEST_P(EGLRobustnessTest,NoErrorByDefault)155 TEST_P(EGLRobustnessTest, NoErrorByDefault)
156 {
157 ANGLE_SKIP_TEST_IF(!mInitialized);
158 ASSERT_TRUE(glGetGraphicsResetStatusEXT() == GL_NO_ERROR);
159 }
160
161 // Checks that the application gets no loss with NO_RESET_NOTIFICATION
TEST_P(EGLRobustnessTest,DISABLED_NoResetNotification)162 TEST_P(EGLRobustnessTest, DISABLED_NoResetNotification)
163 {
164 ANGLE_SKIP_TEST_IF(!mInitialized);
165 createContext(EGL_NO_RESET_NOTIFICATION_EXT);
166
167 if (!IsWindows())
168 {
169 std::cout << "Test disabled on non Windows platforms because drivers can't recover. "
170 << "See " << __FILE__ << ":" << __LINE__ << std::endl;
171 return;
172 }
173 std::cout << "Causing a GPU reset, brace for impact." << std::endl;
174
175 forceContextReset();
176 ASSERT_TRUE(glGetGraphicsResetStatusEXT() == GL_NO_ERROR);
177 }
178
179 // Checks that resetting the ANGLE display allows to get rid of the context loss.
180 // Also checks that the application gets notified of the loss of the display.
181 // We coalesce both tests to reduce the number of TDRs done on Windows: by default
182 // having more than 5 TDRs in a minute will cause Windows to disable the GPU until
183 // the computer is rebooted.
TEST_P(EGLRobustnessTest,DISABLED_ResettingDisplayWorks)184 TEST_P(EGLRobustnessTest, DISABLED_ResettingDisplayWorks)
185 {
186 // Note that on Windows the OpenGL driver fails hard (popup that closes the application)
187 // on a TDR caused by D3D. Don't run D3D tests at the same time as the OpenGL tests.
188 ANGLE_SKIP_TEST_IF(IsWindows() && isGLRenderer());
189 ANGLE_SKIP_TEST_IF(!mInitialized);
190
191 createContext(EGL_LOSE_CONTEXT_ON_RESET_EXT);
192
193 if (!IsWindows())
194 {
195 std::cout << "Test disabled on non Windows platforms because drivers can't recover. "
196 << "See " << __FILE__ << ":" << __LINE__ << std::endl;
197 return;
198 }
199 std::cout << "Causing a GPU reset, brace for impact." << std::endl;
200
201 forceContextReset();
202 ASSERT_TRUE(glGetGraphicsResetStatusEXT() != GL_NO_ERROR);
203
204 recreateTestFixture();
205 ASSERT_TRUE(glGetGraphicsResetStatusEXT() == GL_NO_ERROR);
206 }
207
208 ANGLE_INSTANTIATE_TEST(EGLRobustnessTest,
209 WithNoFixture(ES2_VULKAN()),
210 WithNoFixture(ES2_D3D9()),
211 WithNoFixture(ES2_D3D11()),
212 WithNoFixture(ES2_OPENGL()));
213