1 //
2 // Copyright 2017 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 // EGLSurfacelessContextTest.cpp:
8 // Tests for the EGL_KHR_surfaceless_context and GL_OES_surfaceless_context
9
10 #include <gtest/gtest.h>
11
12 #include "test_utils/ANGLETest.h"
13 #include "test_utils/angle_test_configs.h"
14 #include "test_utils/gl_raii.h"
15
16 using namespace angle;
17
18 namespace
19 {
20
21 class EGLSurfacelessContextTest : public ANGLETest<>
22 {
23 public:
EGLSurfacelessContextTest()24 EGLSurfacelessContextTest() : mDisplay(0) {}
25
testSetUp()26 void testSetUp() override
27 {
28 EGLAttrib dispattrs[3] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(),
29 EGL_NONE};
30 mDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
31 reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
32 ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY);
33
34 ASSERT_EGL_TRUE(eglInitialize(mDisplay, nullptr, nullptr));
35
36 int nConfigs = 0;
37 ASSERT_EGL_TRUE(eglGetConfigs(mDisplay, nullptr, 0, &nConfigs));
38 ASSERT_TRUE(nConfigs != 0);
39
40 int nReturnedConfigs = 0;
41 std::vector<EGLConfig> configs(nConfigs);
42 ASSERT_EGL_TRUE(eglGetConfigs(mDisplay, configs.data(), nConfigs, &nReturnedConfigs));
43 ASSERT_TRUE(nConfigs == nReturnedConfigs);
44
45 for (auto config : configs)
46 {
47 EGLint surfaceType;
48 eglGetConfigAttrib(mDisplay, config, EGL_SURFACE_TYPE, &surfaceType);
49 if (surfaceType & EGL_PBUFFER_BIT)
50 {
51 mConfig = config;
52 mSupportsPbuffers = true;
53 break;
54 }
55 }
56
57 if (!mConfig)
58 {
59 mConfig = configs[0];
60 }
61
62 ASSERT_NE(nullptr, mConfig);
63 }
64
testTearDown()65 void testTearDown() override
66 {
67 eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
68
69 if (mContext != EGL_NO_CONTEXT)
70 {
71 eglDestroyContext(mDisplay, mContext);
72 }
73
74 if (mPbuffer != EGL_NO_SURFACE)
75 {
76 eglDestroySurface(mDisplay, mPbuffer);
77 }
78
79 eglTerminate(mDisplay);
80 }
81
82 protected:
createContext()83 EGLContext createContext()
84 {
85 const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
86
87 mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, contextAttribs);
88 EXPECT_TRUE(mContext != EGL_NO_CONTEXT);
89 return mContext;
90 }
91
createPbuffer(int width,int height)92 EGLSurface createPbuffer(int width, int height)
93 {
94 if (!mSupportsPbuffers)
95 {
96 return EGL_NO_SURFACE;
97 }
98
99 const EGLint pbufferAttribs[] = {
100 EGL_WIDTH, 500, EGL_HEIGHT, 500, EGL_NONE,
101 };
102 mPbuffer = eglCreatePbufferSurface(mDisplay, mConfig, pbufferAttribs);
103 EXPECT_TRUE(mPbuffer != EGL_NO_SURFACE);
104 return mPbuffer;
105 }
106
createFramebuffer(GLFramebuffer * fbo,GLTexture * tex) const107 void createFramebuffer(GLFramebuffer *fbo, GLTexture *tex) const
108 {
109 glBindFramebuffer(GL_FRAMEBUFFER, fbo->get());
110
111 glBindTexture(GL_TEXTURE_2D, tex->get());
112 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 500, 500, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
113
114 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex->get(), 0);
115 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
116 }
117
checkExtension(bool verbose=true) const118 bool checkExtension(bool verbose = true) const
119 {
120 if (!IsEGLDisplayExtensionEnabled(mDisplay, "EGL_KHR_surfaceless_context"))
121 {
122 if (verbose)
123 {
124 std::cout << "Test skipped because EGL_KHR_surfaceless_context is not available."
125 << std::endl;
126 }
127 return false;
128 }
129 return true;
130 }
131
132 EGLContext mContext = EGL_NO_CONTEXT;
133 EGLSurface mPbuffer = EGL_NO_SURFACE;
134 bool mSupportsPbuffers = false;
135 EGLConfig mConfig = 0;
136 EGLDisplay mDisplay = EGL_NO_DISPLAY;
137 };
138
139 // Test surfaceless MakeCurrent returns the correct value.
TEST_P(EGLSurfacelessContextTest,MakeCurrentSurfaceless)140 TEST_P(EGLSurfacelessContextTest, MakeCurrentSurfaceless)
141 {
142 EGLContext context = createContext();
143
144 if (eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context))
145 {
146 ASSERT_TRUE(checkExtension(false));
147 }
148 else
149 {
150 // The extension allows EGL_BAD_MATCH with the extension too, but ANGLE
151 // shouldn't do that.
152 ASSERT_FALSE(checkExtension(false));
153 }
154 }
155
156 // Test that the scissor and viewport are set correctly
TEST_P(EGLSurfacelessContextTest,DefaultScissorAndViewport)157 TEST_P(EGLSurfacelessContextTest, DefaultScissorAndViewport)
158 {
159 if (!checkExtension())
160 {
161 return;
162 }
163
164 EGLContext context = createContext();
165 ASSERT_EGL_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context));
166
167 GLint scissor[4] = {1, 2, 3, 4};
168 glGetIntegerv(GL_SCISSOR_BOX, scissor);
169 ASSERT_GL_NO_ERROR();
170 ASSERT_EQ(0, scissor[0]);
171 ASSERT_EQ(0, scissor[1]);
172 ASSERT_EQ(0, scissor[2]);
173 ASSERT_EQ(0, scissor[3]);
174
175 GLint viewport[4] = {1, 2, 3, 4};
176 glGetIntegerv(GL_VIEWPORT, viewport);
177 ASSERT_GL_NO_ERROR();
178 ASSERT_EQ(0, viewport[0]);
179 ASSERT_EQ(0, viewport[1]);
180 ASSERT_EQ(0, viewport[2]);
181 ASSERT_EQ(0, viewport[3]);
182 }
183
184 // Test the CheckFramebufferStatus returns the correct value.
TEST_P(EGLSurfacelessContextTest,CheckFramebufferStatus)185 TEST_P(EGLSurfacelessContextTest, CheckFramebufferStatus)
186 {
187 if (!checkExtension())
188 {
189 return;
190 }
191
192 EGLContext context = createContext();
193 ASSERT_EGL_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context));
194
195 ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_UNDEFINED_OES, glCheckFramebufferStatus(GL_FRAMEBUFFER));
196
197 GLFramebuffer fbo;
198 GLTexture tex;
199 createFramebuffer(&fbo, &tex);
200 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
201 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
202 }
203
204 // Test that clearing and readpixels work when done in an FBO.
TEST_P(EGLSurfacelessContextTest,ClearReadPixelsInFBO)205 TEST_P(EGLSurfacelessContextTest, ClearReadPixelsInFBO)
206 {
207 if (!checkExtension())
208 {
209 return;
210 }
211
212 EGLContext context = createContext();
213 ASSERT_EGL_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context));
214
215 GLFramebuffer fbo;
216 GLTexture tex;
217 createFramebuffer(&fbo, &tex);
218 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
219
220 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
221 glClear(GL_COLOR_BUFFER_BIT);
222 ASSERT_GL_NO_ERROR();
223
224 EXPECT_PIXEL_COLOR_EQ(250, 250, GLColor::red);
225 ASSERT_GL_NO_ERROR();
226 }
227
228 // Test clear+readpixels in an FBO in surfaceless and in the default FBO in a pbuffer
TEST_P(EGLSurfacelessContextTest,Switcheroo)229 TEST_P(EGLSurfacelessContextTest, Switcheroo)
230 {
231 ANGLE_SKIP_TEST_IF(!checkExtension());
232 ANGLE_SKIP_TEST_IF(!mSupportsPbuffers);
233
234 // Fails on NVIDIA Shield TV (http://anglebug.com/42263498)
235 ANGLE_SKIP_TEST_IF(IsAndroid() && IsNVIDIA());
236
237 EGLContext context = createContext();
238 EGLSurface pbuffer = createPbuffer(500, 500);
239
240 // We need to make the context current to do the one time setup of the FBO
241 ASSERT_EGL_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context));
242 GLFramebuffer fbo;
243 GLTexture tex;
244 createFramebuffer(&fbo, &tex);
245 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
246
247 for (int i = 0; i < 4; ++i)
248 {
249 // Clear to red in the FBO in surfaceless mode
250 ASSERT_EGL_TRUE(eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context));
251
252 glBindFramebuffer(GL_FRAMEBUFFER, fbo.get());
253 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
254 glClear(GL_COLOR_BUFFER_BIT);
255 ASSERT_GL_NO_ERROR();
256
257 EXPECT_PIXEL_COLOR_EQ(250, 250, GLColor::red);
258 ASSERT_GL_NO_ERROR();
259
260 // Clear to green in the pbuffer
261 ASSERT_EGL_TRUE(eglMakeCurrent(mDisplay, pbuffer, pbuffer, context));
262
263 glBindFramebuffer(GL_FRAMEBUFFER, 0);
264 glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
265 glClear(GL_COLOR_BUFFER_BIT);
266 ASSERT_GL_NO_ERROR();
267
268 EXPECT_PIXEL_COLOR_EQ(250, 250, GLColor::green);
269 ASSERT_GL_NO_ERROR();
270 }
271 }
272
273 } // anonymous namespace
274
275 ANGLE_INSTANTIATE_TEST(EGLSurfacelessContextTest,
276 WithNoFixture(ES2_D3D9()),
277 WithNoFixture(ES2_D3D11()),
278 WithNoFixture(ES2_METAL()),
279 WithNoFixture(ES2_OPENGL()),
280 WithNoFixture(ES2_OPENGLES()),
281 WithNoFixture(ES2_VULKAN()));
282