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