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