xref: /aosp_15_r20/external/angle/src/tests/egl_tests/EGLSurfacelessContextTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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