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